Home  >  Article  >  Backend Development  >  How do I reliably check for a request cancellation error in Go, even if it has been wrapped by another error?

How do I reliably check for a request cancellation error in Go, even if it has been wrapped by another error?

DDD
DDDOriginal
2024-11-08 04:08:01254browse

How do I reliably check for a request cancellation error in Go, even if it has been wrapped by another error?

Checking Request Cancellation in Go

In Go, determining whether a request has been cancelled can be a challenge. Consider the following code:

package main

import (
    "context"
    "log"
    "net/http"
)

func main() {
    r, _ := http.NewRequest("GET", "http://example.com", nil)
    ctx, cancel := context.WithCancel(context.Background())
    r = r.WithContext(ctx)
    ch := make(chan bool)
    go func() {
        _, err := http.DefaultClient.Do(r)
        log.Println(err == context.Canceled)
        ch <- true
    }()
    cancel()
    <-ch
}

Surprisingly, this code prints false in Go 1.9 even though the request should have been cancelled.

Correct Approach

In more recent versions of Go, a better way to check for cancellation is to use the errors.Is function introduced in Go 1.13. Here's an updated version of the code:

import (
    "context"
    "errors"
    "log"
    "net/http"
)

func main() {
    // Create a context that is already canceled
    ctx, cancel := context.WithCancel(context.Background())
    cancel()

    // Create the request with it
    r, _ := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil)

    // Do it, it will immediately fail because the context is canceled.
    _, err := http.DefaultClient.Do(r)
    log.Println(err) // Get http://example.com: context canceled

    // This prints false, because the http client wraps the context.Canceled
    // error into another one with extra information.
    log.Println(err == context.Canceled)

    // This prints true, because errors.Is checks all the errors in the wrap chain,
    // and returns true if any of them matches.
    log.Println(errors.Is(err, context.Canceled))
}

By using errors.Is, we can reliably check if the underlying error is a context cancellation error, even if it has been wrapped by another error. The errors.Is function will traverse the entire chain of errors and return true if any of them matches the given error type.

The above is the detailed content of How do I reliably check for a request cancellation error in Go, even if it has been wrapped by another error?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn