Files
gotenberg/pkg/modules/webhook/pool_safe_context.go
2026-09-16 19:38:45 +02:00

35 lines
1.3 KiB
Go

package webhook
import (
"github.com/labstack/echo/v5"
)
// newDetachedContext returns an [echo.Context] carrying a snapshot of the given
// keys, detached from Echo's context pool.
//
// Echo returns an [echo.Context] to its sync.Pool as soon as the synchronous
// handler returns, including when the webhook middleware returns
// [api.ErrAsyncProcess]. A concurrent request can then claim the recycled
// context and c.Reset() wipes the shared store out from under the webhook
// goroutine, which causes any `c.Get("logger").(*slog.Logger)`-style assertion
// further down the chain to panic on a nil value.
//
// [echo.NewContext] allocates outside the pool, so recycling cannot reach the
// returned context. Keys absent from c are omitted; the returned context still
// returns nil for them, matching [echo.Context.Get] behavior.
//
// Only the asynchronous path uses this. Nothing downstream of the webhook
// middleware writes to the response: contextMiddleware sits upstream and has
// already answered 204 by the time the goroutine runs.
func newDetachedContext(c *echo.Context, keys ...string) *echo.Context {
detached := echo.NewContext(c.Request(), c.Response(), c.Echo())
for _, key := range keys {
if v := c.Get(key); v != nil {
detached.Set(key, v)
}
}
return detached
}