fix(project_events): use process-lifetime ctx for async SSE publish #8
@@ -22,6 +22,7 @@ import (
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/eventsource"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
@@ -317,8 +318,16 @@ func PublishProjectDeleted(ctx context.Context, payload ProjectDeleted) {
|
||||
go publishEvent(detach(ctx), payload.ProjectID, payload)
|
||||
}
|
||||
|
||||
// detach strips cancellation/deadline from ctx but preserves stored
|
||||
// values (notably the session tag) so the goroutine outlives the request.
|
||||
func detach(ctx context.Context) context.Context {
|
||||
return context.WithoutCancel(ctx)
|
||||
// detach returns a context safe for use in the fire-and-forget publish
|
||||
// goroutine. The request's context carries a request-scoped DB session
|
||||
// that is returned to the pool once the HTTP handler completes; reusing
|
||||
// it from the goroutine races with that teardown and makes subsequent
|
||||
// queries (GetProjectByID, access checks) fail intermittently. The
|
||||
// session tag is already resolved synchronously before the goroutine
|
||||
// starts, so the goroutine needs no request-scoped values — only a
|
||||
// clean, process-lifetime DB context. ShutdownContext is backed by the
|
||||
// global engine, outlives any single request, and is cancelled on app
|
||||
// shutdown so we don't leak goroutines past teardown.
|
||||
func detach(_ context.Context) context.Context {
|
||||
return graceful.GetManager().ShutdownContext()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user