Hi, Just wondering if there is a way to use context when using this library?
Right now it is used only for passing some data with the client instance context. How would you like to use it?
I would like to use context in the same way request.WithContext works where the context can cancel the redis request if it is canceled or timed out.
It could also help instrumentation.
With request:
ctx := context.WithTimeout(...) // OR WithCancel | WithDeadline | ...
reqNoCtx, err := http.NewRequest(...)
if err != nil {
return err
}
req := reqNoCtx.WithContext(ctx)
What it could look like in go-redis right now:
client.WithContext(ctx) // Same connection pool but with a specific context for operations
client.Get(...)
Or nicer with a redis.ContextClient:
ctxClient.Get(ctx, ...)
What is the use case for canceling Redis request? Is not Options.ReadTimeout enough?
Yes, it might be. I am just asking this question because I am used to passing context objects around to easily cancel work done when an incoming http request is cancelled or its computation is taking too long.
The difference between ReadTimeout and Context, is that the ReadTimeout is per redis operations where the context could have been created at the start of an incoming http request and passed down to the redis operation (edit: and also to many redis operations).
It might be a non issue, I was just wondering if the Context/WithContext of client would be doing what I expected them to do. And the answer is no in favor of using ReadTimeout which is a totally good solution. Thanks.
I'll close the issue now, thanks for the answers.
Let's keep this open for future references.
Overall go-redis could use ctx.Deadline() and set it on the underlying connection, e.g.
ctx, _ := context.WithTImeout(context.TODO(), time.Second)
client.WithContext(ctx).Get()
will result in something like
conn := pool.Get()
tm, ok := ctx.Deadline()
if ok {
conn.SetReadDeadline(tm)
conn.SetWriteDeadline(tm)
}
It should not be hard to do and can be occasionally useful...
There is also context.WithCancel. If a user aborts their http request you can use ctx.Done() to cancel the in-progress request.
I have a scenario which could benefit from having the possibility of cancelling a Redis operation via a context:
I run an app which spawns multiple goroutines and which needs to exit gracefully when it receives SIGTERM.
Some of the goroutines are connecting to Redis to perform operations; if the server has stopped responding, the goroutine(s) attempting to connect will be frozen. If at this point I try to gracefully terminate the program, because the Redis client doesn't support cancelling via context, I'll have to wait for DialTimeout to occur until the goroutine can check ctx.Done() and exit.
Or, similarly, if I want to terminate during a long(er) Redis operation (e.g the app is doing KEYS * even though it's not a good practice), I need to wait until completion before the app can exit.
@lcosmin I have the same situation as yours. Did you manage to find a way to achieve that behaviour? Moreover it can become even trickier if the involved redis operation is blocking (eg. BRPOPLPUSH) and with a timeout that isn't that short.
@cog-qlik I don't remember exactly, but I'm pretty sure that the solution I used was to have a low timeout value.
If i understand the code correctly, read and write timeouts are used during writing and reading from particular node. An operation in redis cluster may require several operations (e.g. in case of MOVED response) and i would like to be able to specify timeout for the whole operation.
Context support would really help.
+1 for being able to cancel or timeout the entire operation. The scenario I'm encountering is that the http service times out and responds with an error, but the redis-go client continues to work on the request in a separate goroutine. Ideally once the original request context times out or is canceled, all work is halted
generally context is good idea. Timeout is nice, however imagine that in most cases you need 3s timeout and in one case you need 10s. Your timeout needs to be 10s even though it unnecessary. As mentioned if you have worker or any long running operation context is nice as you can cancel that thing.
This should be addressed in master branch / to be released v7. go-redis checks Context.Done when allocating a connection to process a command and respects Context.Deadline to set read/write deadline. That should not affect performance and should be enough to cover majority of use cases.
Thanks a lot for the information @vmihailenco . Any ETA for the new release?
Any plan on adding .WithContext to UniversalClient?
Type system does not allow that since WithContext has different return type in each case.
Most helpful comment
+1 for being able to cancel or timeout the entire operation. The scenario I'm encountering is that the http service times out and responds with an error, but the redis-go client continues to work on the request in a separate goroutine. Ideally once the original request context times out or is canceled, all work is halted