mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-16 04:12:16 +01:00
fix(webhook): detach context from request lifecycle to prevent cancellation in async mode
This commit is contained in:
committed by
Julien Neuhart
parent
e14cab0c8b
commit
463bb2f91c
@@ -27,7 +27,7 @@ func TestNewContext_Cancellation(t *testing.T) {
|
|||||||
t.Fatalf("failed to close multipart writer: %v", err)
|
t.Fatalf("failed to close multipart writer: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a request with a cancellable context.
|
// Create a request with a cancellable context.
|
||||||
reqCtx, cancelReq := context.WithCancel(context.Background())
|
reqCtx, cancelReq := context.WithCancel(context.Background())
|
||||||
req := httptest.NewRequest(http.MethodPost, "/", body).WithContext(reqCtx)
|
req := httptest.NewRequest(http.MethodPost, "/", body).WithContext(reqCtx)
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
@@ -48,7 +48,7 @@ func TestNewContext_Cancellation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Verify initial state: context SHOULD NOT be done yet.
|
// Verify initial state: context SHOULD NOT be done yet.
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
t.Fatal("context should not be done immediately")
|
t.Fatal("context should not be done immediately")
|
||||||
|
|||||||
@@ -272,6 +272,29 @@ func webhookMiddleware(w *Webhook) api.Middleware {
|
|||||||
})
|
})
|
||||||
return c.NoContent(http.StatusNoContent)
|
return c.NoContent(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
// Create a new context derived from Background (detached from Request)
|
||||||
|
// but with the same deadline as the original context.
|
||||||
|
detachedCtx, detachedCancel := context.WithDeadline(context.Background(), deadline)
|
||||||
|
|
||||||
|
// Replace the embedded context in the api.Context struct.
|
||||||
|
// The modules downstream will now use this detached context.
|
||||||
|
ctx.Context = detachedCtx
|
||||||
|
|
||||||
|
// We must wrap the cancel function.
|
||||||
|
// 1. detachedCancel() cleans up our new detached context.
|
||||||
|
// 2. originalCancel() (captured from c.Get("cancel")) cleans up the working directory.
|
||||||
|
originalCancel := cancel
|
||||||
|
cancel = func() {
|
||||||
|
detachedCancel()
|
||||||
|
originalCancel()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback if no deadline was set (rare, as newContext enforces it).
|
||||||
|
ctx.Context = context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
// As a webhook URL has been given, we handle the request in a
|
// As a webhook URL has been given, we handle the request in a
|
||||||
// goroutine and return immediately.
|
// goroutine and return immediately.
|
||||||
w.asyncCount.Add(1)
|
w.asyncCount.Add(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user