@@ -21,9 +21,11 @@ def setup_once():
2121 old_build_tracer = trace .build_tracer
2222
2323 def sentry_build_tracer (name , task , * args , ** kwargs ):
24- task .__call__ = _wrap_task_call (task , task .__call__ )
25- task .run = _wrap_task_call (task , task .run )
26- return old_build_tracer (name , task , * args , ** kwargs )
24+ # Need to patch both methods because older celery sometimes
25+ # short-circuits to task.run if it thinks it's safe.
26+ task .__call__ = _wrap_task_call (task .__call__ )
27+ task .run = _wrap_task_call (task .run )
28+ return _wrap_tracer (task , old_build_tracer (name , task , * args , ** kwargs ))
2729
2830 trace .build_tracer = sentry_build_tracer
2931
@@ -33,28 +35,40 @@ def sentry_build_tracer(name, task, *args, **kwargs):
3335 ignore_logger ("celery.worker.job" )
3436
3537
36- def _wrap_task_call (self , f ):
38+ def _wrap_tracer (task , f ):
39+ # Need to wrap tracer for pushing the scope before prerun is sent, and
40+ # popping it after postrun is sent.
41+ #
42+ # This is the reason we don't use signals for hooking in the first place.
43+ # Also because in Celery 3, signal dispatch returns early if one handler
44+ # crashes.
3745 def _inner (* args , ** kwargs ):
3846 hub = Hub .current
3947 if hub .get_integration (CeleryIntegration ) is None :
4048 return f (* args , ** kwargs )
4149
42- with hub .configure_scope () as scope :
43- if scope ._name == "celery" :
44- return f (* args , ** kwargs )
45-
4650 with hub .push_scope () as scope :
4751 scope ._name = "celery"
48- scope .add_event_processor (_make_event_processor (args , kwargs , self ))
49- try :
50- return f (* args , ** kwargs )
51- except Exception :
52- reraise (* _capture_exception (hub ))
52+ scope .add_event_processor (_make_event_processor (task , * args , ** kwargs ))
53+
54+ return f (* args , ** kwargs )
55+
56+ return _inner
57+
58+
59+ def _wrap_task_call (f ):
60+ # Need to wrap task call because the exception is caught before we get to
61+ # see it. Also celery's reported stacktrace is untrustworthy.
62+ def _inner (* args , ** kwargs ):
63+ try :
64+ return f (* args , ** kwargs )
65+ except Exception :
66+ reraise (* _capture_exception ())
5367
5468 return _inner
5569
5670
57- def _make_event_processor (args , kwargs , task ):
71+ def _make_event_processor (task , uuid , args , kwargs , request = None ):
5872 def event_processor (event , hint ):
5973 with capture_internal_exceptions ():
6074 event ["transaction" ] = task .name
@@ -87,12 +101,15 @@ def event_processor(event, hint):
87101 return event_processor
88102
89103
90- def _capture_exception (hub ):
91- exc_info = sys .exc_info ()
92- event , hint = event_from_exception (
93- exc_info ,
94- client_options = hub .client .options ,
95- mechanism = {"type" : "celery" , "handled" : False },
96- )
97- hub .capture_event (event , hint = hint )
104+ def _capture_exception ():
105+ hub = Hub .current
106+ if hub .get_integration (CeleryIntegration ) is not None :
107+ exc_info = sys .exc_info ()
108+ event , hint = event_from_exception (
109+ exc_info ,
110+ client_options = hub .client .options ,
111+ mechanism = {"type" : "celery" , "handled" : False },
112+ )
113+ hub .capture_event (event , hint = hint )
114+
98115 return exc_info
0 commit comments