Home > Backend Development > Golang > Handling cross-layer context cancellation

Handling cross-layer context cancellation

WBOY
Release: 2024-02-05 23:54:07
forward
506 people have browsed it

Handling cross-layer context cancellation

Question content

I am developing a layered backend API with controllers, services, repositories, etc.

Context

Each method in these layers takes context.Context as its first parameter containing the request context. This is convenient because any method can access various request-related data (such as correlationID, etc.)

Each request context has a timeout set by the following TimeoutMiddleware:

func TimeoutMiddleware(timeoutFn func(*gin.Context) time.Duration) gin.HandlerFunc {
    return func(c *gin.Context) {
        timeout := timeoutFn(c)
        ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
        defer cancel()

        c.Request = c.Request.WithContext(ctx)

        c.Next()
    }
}

func TimeoutFn(c *gin.Context) time.Duration {
    return conf.HTTPRouter.DefaultContextTimeout
}
Copy after login

challenge

The idea is to gracefully stop any ongoing operations when the request context times out. Based on my understanding of context and concurrency (very little), I built this helper function:

package helpers

import "context"

// Checks for context cancellation and returns ctx.Err() if canceled.
func HandleContextCancel(ctx context.Context) error {
    select {
    case <-ctx.Done(): // If the context is canceled
        return ctx.Err() // return immediately with the canceled error.

    default: 
        return nil // Continue with the normal processing.
    }
}

Copy after login

In theory, if I wanted to stop any operation as quickly as possible, I would need to call this function at the beginning of every method in the application, like this: < /p>

func DoSomething(ctx context.Context, ...) resterrors.RestErr {
if err := helpers.HandleContextCancel(ctx); err != nil {
    return resterrors.NewRequestTimeoutError(
        fmt.Errorf("DoSomething: %w", err),
    )
}
// ...
Copy after login

Also, I know that in the repository that accesses the database, most functions require a Context, such as Query, QueryRow, Exec ...,As follows:

rows, err := pgclient.GetSession().Query(ctx, query, param1, ...)
Copy after login

So every time an error occurs in the line above, I have to check if the error is not due to context cancellation instead of just returning internal_server_error and the error message like this:

rows, err := pgclient.GetSession().Query(ctx, query, param1, ...)
if err != nil {
   return helpers.MapRepoError("DoSomething: Query Error:", err)
}
Copy after login
func MapRepoError(location string, err error) resterrors.RestErr {
    if errors.Is(err, context.DeadlineExceeded) {
        return resterrors.NewRequestTimeoutError(
            fmt.Errorf("%s request_timeout", location),
        )
    }
    return resterrors.NewInternalServerError(
        fmt.Errorf("%s %w", location, err),
    )
}
Copy after login

Using the HandleContextCancel function looks a bit redundant, what do you think?


Correct answer


You don't need the HandleContextCancel function, you can simply do the following:

if ctx.Err()!=nil {
  // Context timed out or canceled. Return
  return ctx.Err()
}
Copy after login

If your other error handling functions wrap this error correctly (i.e. they implement the Unwrap() error method, then you can check at the top level whether the error contains a timeout/cancellation error and decide if you To handle what type of errors like returns. You don't have to do this for every layer.

The above is the detailed content of Handling cross-layer context cancellation. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
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
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template