feat(taskworker): Add ViewerContext propagation via context hooks#112217
feat(taskworker): Add ViewerContext propagation via context hooks#112217
Conversation
Implement ViewerContextHook that propagates ViewerContext through TaskBroker task headers. On dispatch, the hook reads from the contextvar and injects org_id, user_id, and actor_type into task headers. On execution, it restores the ViewerContext from headers into a viewer_context_scope. This enables implicit identity propagation through async tasks without requiring callsites to manually pass user context. Depends on getsentry/taskbroker#587 for the ContextHook protocol. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| metrics_class=SentryMetricsBackend(), | ||
| router_class=SentryRouter(), | ||
| at_most_once_store=DjangoCacheAtMostOnceStore(cache), | ||
| context_hooks=[ViewerContextHook()], |
There was a problem hiding this comment.
ActorType enum conversion can raise ValueError during version skew
ActorType(actor) on line 156 of adapters.py converts the header value to an enum without catching ValueError. During rolling deployments, if a producer with a newer ActorType value sends tasks to a consumer with an older enum definition, the task execution will crash. This matches Check 4 (Value Validation Errors) pattern: "Integer enum lookups without catching ValueError".
Verification
Read src/sentry/taskworker/adapters.py to trace ViewerContextHook implementation. Verified ActorType is a StrEnum (src/sentry/viewer_context.py:28) with 4 values. The on_execute method (line 156) calls ActorType(actor) without try/except. Cross-process version skew during deployments could cause ValueError if new enum values are added.
Identified by Warden sentry-backend-bugs · 5Z2-2MC
Add
ViewerContextHookthat implicitly propagates ViewerContext through TaskBroker task headers.On dispatch: the hook reads from the
get_viewer_context()contextvar and injectssentry-viewer-org,sentry-viewer-user, andsentry-viewer-actorinto task activation headers. This happens automatically increate_activation()— no callsite changes needed.On execution: the hook reads those headers back and wraps the task callable in
viewer_context_scope(), makingget_viewer_context()available inside every task.This is the Sentry-side implementation. The taskbroker-client
ContextHookprotocol that powers this lives in getsentry/taskbroker#587 — this PR depends on that being merged and thetaskbroker-clientdependency bumped.Part of the ViewerContext RFC.