feature request: allow `UNBLOCK`ing a blocking call before cancelling it to reuse the connection later for better performance
👋 My team enables pipelining for specific requests by using ToPipe when building the command object. This gives us the following behavior when a blocking request is made.
- Rueidis tries to acquire a wire (a wrapper around a connection) from the dedicated pool.
- If the pool has no available connections, we create a new pipe (pipe is an implementation of the wire interface).
- We execute the command
- If the request is successful, we return the wire to the dedicated pool. The wire will be reused on the next request.
- If the request’s context is cancelled (or fails for some other reason like a network timeout), we try to return the wire back to the dedicated pool, but because the wire is closed, the pool does not accept it. A new wire will be created for subsequent requests.
This solves the problem of ensuring we don’t open too many connections, but has the downside that every time we cancel a blocking call, the connection is closed. It would be more performant to issue an UNBLOCK command (which tells Redis to stop blocking), and then we can reuse the connection.
Is this a reasonable feature request? If so, are you open to contributions?
Hi @davidxia, nice to meet you here!
I think that is a worthwhile optimization! We are open to contributions for sure.
So, I think the optimization for the blocking .Do() should be done inside this block:
https://github.com/redis/rueidis/blob/5b78011c2f17d089378f48ca0997b8e1b7edc392/mux.go#L269-L271
And it should look like the following:
- Check whether the
cmdis a blocking command or not; If not, then we should close the wire and return it to the pool directly and skip all the following procedures. - Check whether the
resp.NonRedisError()is a context error; If not, then we should close the wire and return it to the pool directly and skip all the following procedures. - Check whether
wire.Error()is nil or not; if not, then the wire is already closed. We should return the wire to the pool directly and skip all the following procedures. - Now, we can do the
UNBLOCK: We don't close the wire and don't return it to the pool in the currentm.blockingfunction. Instead, we need to create another goroutine to send theUNBLOCKcommand withm.pipeline(context.Background(), unblock)and only return the wire to the pool without closing it when theUNBLOCKcommand gets a response saying that the wire is unblocked successfully; Otherwise, we still close the wire before returning it to the pool.
@rueian yes, I was glad to see you're the maintainer of this project! Thanks so much for the guidance. I'll make a PR soon. 🙏
Hi @davidxia, do you need any help?
Hi @davidxia, do you need any help?
I haven't gotten around to this yet. Will take a look today or early next week!