27

I am having trouble understanding how I can check if context exceeded deadline set by timeout, or if I should check at all?

This is a snippet from mongo-go-driver:

client, err := NewClient("mongodb://foo:bar@localhost:27017")
if err != nil { return err }
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil { return err }

Reading this code, how do I know if context exceeded deadline? From what I naively understand (or not understand), the line err = client.Connect(ctx) will give me error including deadline exceeded (if exceeded), thus I think I don't even need to explicitly check?

But then while looking around the internet to better understand how contexts work, I come across uses of select cases which explicitly checks contexts as below (code snippet from http://p.agnihotry.com/post/understanding_the_context_package_in_golang/):

//Use a select statement to exit out if context expires
  select {
  case <-ctx.Done():
    fmt.Println("sleepRandomContext: Time to return")
  case sleeptime := <-sleeptimeChan:
    //This case is selected when processing finishes before the context is cancelled
    fmt.Println("Slept for ", sleeptime, "ms")
  }

Should I be explicitly checking for it? If not, when should I use explicit checks?

2 Answers 2

14

The select code in the second part of your question is what the code in the Connect method might look like. There it is checking whether the ctx.Done() is ready to send. If it is, then the context was cancelled either because the timeout occurred, or because cancel() was called.

errors are values. Treat them as such. If it is important for you to understand the cause of the error (network down? unexpected data? timeout?) then you should do the check and act accordingly. If recovery from the error regardless of the cause is the same, then checking the error is not as important.

Sign up to request clarification or add additional context in comments.

2 Comments

Can you verify that I am understanding what you are saying? So if I am using an outsource package like mongo-go-driver, and their functions take in a context, I can safely assume that they will handle the context for me? Meaning somewhere down the line, if timeout exceeded, this function will just return an err (that will probably say "deadline exceeded"). Bottom line, I would generally only worry about err != nil?
@Leesa Close, but not quite. You end up with the cancel function as well, which you can call and which the driver should but is not required to honor. But looking over the code, you can see at lease one place they do check for a cancelled / timed-out context.
13

A context is best used to manage the lifecycle of something. Therefore if you are doing something (e.g., processing a file), then you should be checking the context to ensure the process hasn't been processed.

There are two ways to check if a context has been cancelled or timed out:

  1. Context.Done() - This returns a channel that will be closed when the context is cancelled.
  2. Context.Err() - This will return an error if the context is cancelled.

Pick the one that best suits your needs. If you are doing things with channels, then using the context.Done() in a select works well. If you are using a for loop while reading an io.Reader, then checking context.Err() is easier.

All that being said, if you are starting something that also takes a context, you should always use the context you already have if you would want that new "thing" to be cancelled if you were cancelled.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.