Get and Set context #8

Closed
opened 2025-08-27 12:17:09 +00:00 by mybigman · 5 comments

How do I go about getting/setting context?

func Timeout(timeout time.Duration) web.Handler {
	return func(ctx web.Context) error {
		// we need request context here
		ctxWithTimeout, cancel := context.WithTimeout(r.Context(), timeout)
		defer func() {
			cancel()
			if ctxWithTimeout.Err() == context.DeadlineExceeded {
				ctx.Response().SetStatus(http.StatusGatewayTimeout)
			}
		}()

		// r = r.WithContext(ctx)
		// need to pass the wrapped context here
		return ctx.Next(r)
	}
}
How do I go about getting/setting context? ```go func Timeout(timeout time.Duration) web.Handler { return func(ctx web.Context) error { // we need request context here ctxWithTimeout, cancel := context.WithTimeout(r.Context(), timeout) defer func() { cancel() if ctxWithTimeout.Err() == context.DeadlineExceeded { ctx.Response().SetStatus(http.StatusGatewayTimeout) } }() // r = r.WithContext(ctx) // need to pass the wrapped context here return ctx.Next(r) } } ```
Owner

I think you want custom contexts if I understand this correctly?

I think you want [custom contexts](https://git.urbach.dev/go/web#example-custom-contexts) if I understand this correctly?
ed self-assigned this 2025-08-27 12:33:13 +00:00
Author

I did it like this and it appears to be working ok... not sure if it the right approach.

Its using your custom contexts

type TimeoutContext struct {
	web.Context
}

func Timeout(timeout time.Duration) web.Handler {
	return func(ctx web.Context) error {
		timeoutCtx, cancel := context.WithTimeout(context.Background(), timeout)
		defer cancel()

		wrappedCtx := &TimeoutContext{
			Context: ctx,
		}

		// capture the result of the next handler
		resultChan := make(chan error, 1)

		go func() {
			resultChan <- wrappedCtx.Next(wrappedCtx)
		}()

		// wait for timeout or completion
		select {
		case <-timeoutCtx.Done():
			if timeoutCtx.Err() == context.DeadlineExceeded {
				ctx.Response().SetStatus(http.StatusGatewayTimeout)
				ctx.Response().Write([]byte("Request Timeout"))

				return fmt.Errorf("request timeout after %v", timeout)
			}

			return nil

		case err := <-resultChan:
			return err
		}
	}
}
I did it like this and it appears to be working ok... not sure if it the right approach. Its using your custom contexts ```go type TimeoutContext struct { web.Context } func Timeout(timeout time.Duration) web.Handler { return func(ctx web.Context) error { timeoutCtx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() wrappedCtx := &TimeoutContext{ Context: ctx, } // capture the result of the next handler resultChan := make(chan error, 1) go func() { resultChan <- wrappedCtx.Next(wrappedCtx) }() // wait for timeout or completion select { case <-timeoutCtx.Done(): if timeoutCtx.Err() == context.DeadlineExceeded { ctx.Response().SetStatus(http.StatusGatewayTimeout) ctx.Response().Write([]byte("Request Timeout")) return fmt.Errorf("request timeout after %v", timeout) } return nil case err := <-resultChan: return err } } } ```
Owner

Maybe you can do a simple test with a time.Sleep() in the response and see if that code works or not.

Maybe you can do a simple test with a `time.Sleep()` in the response and see if that code works or not.
Owner

Just throwing this in, the server is meant to be used behind a reverse proxy.
It is not designed to communicate with the raw internet directly.

A minimal HTTP/1.1 web server that sits behind a reverse proxy like caddy, haproxy or nginx for HTTP 1/2/3 support.
Just throwing this in, the server is meant to be used behind a reverse proxy. It is **not** designed to communicate with the raw internet directly. ``` A minimal HTTP/1.1 web server that sits behind a reverse proxy like caddy, haproxy or nginx for HTTP 1/2/3 support. ```
Author

all good, I always run behind HAProxxy. was just playing around with some testing.

all good, I always run behind HAProxxy. was just playing around with some testing.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: go/web#8
No description provided.