0

I'm using apscheduler to process few things in background.

I'd like to capture and report possible exceptions to Sentry. My code looks like this:

sentry = Client(dsn=SENTRY_DSN)

def sample_method():
     # some processing..

     raise ConnectionError

def listen_to_exceptions(event):
    if event.exception:
        # I was hoping raven will capture the exception using  sys.exc_info(), but it's not
        sentry.captureException()


scheduler = BlockingScheduler()

scheduler.add_listener(listen_to_exceptions, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)

scheduler.add_job(sample_method, 'interval', minutes=5, max_instances=1)

# run forever!!!
scheduler.start()

But instead capturing the exception, it generates more exceptions trying to report it to Sentry.

ConnectionError
Error notifying listener
Traceback (most recent call last):
  File "/.../venv/lib/python3.6/site-packages/apscheduler/schedulers/base.py", line 825, in _dispatch_event
    cb(event)
  File "app.py", line 114, in listen_to_exceptions
    sentry.captureException(event.exception)
  File "/.../venv/lib/python3.6/site-packages/raven/base.py", line 814, in captureException
    'raven.events.Exception', exc_info=exc_info, **kwargs)
  File "/.../venv/lib/python3.6/site-packages/raven/base.py", line 623, in capture
    if self.skip_error_for_logging(exc_info):
  File "/.../venv/lib/python3.6/site-packages/raven/base.py", line 358, in skip_error_for_logging
    key = self._get_exception_key(exc_info)
  File "/.../venv/lib/python3.6/site-packages/raven/base.py", line 345, in _get_exception_key
    code_id = id(exc_info[2] and exc_info[2].tb_frame.f_code)
TypeError: 'ConnectionError' object is not subscriptable

I'm trying to use event listener according to the docs. Is there another way to capture exceptions in executed jobs?

Of course I could add try except blocks to each job function. I'm just trying to understand if there's a way to do it with apscedular, because I've 20+ jobs and adding sentry.captureException() every where seems like repetition.

EastSw
  • 927
  • 1
  • 9
  • 28
  • Your sample code does not match the traceback. In the traceback you're calling `sentry.captureException(event.exception)` which is not what the Sentry documentation says you should do. – Alex Grönholm Jan 21 '18 at 12:30

2 Answers2

3

You only need to capture EVENT_JOB_ERROR. Also, sentry.captureException() requires an exc_info tuple as its argument, not the exception object. The following will work on Python 3:

def listen_to_exceptions(event):
    exc_info = type(event.exception), event.exception, event.exception.__traceback__
    sentry.captureException(exc_info)

scheduler.add_listener(listen_to_exceptions, EVENT_JOB_ERROR)
Alex Grönholm
  • 5,563
  • 29
  • 32
3

The documentation has been updated. So you have to do it the following way:

from sentry_sdk import capture_exception
....
def sentry_listener(event):
    if event.exception:
        capture_exception(event.exception)

scheduler.add_listener(sentry_listener, EVENT_JOB_ERROR)
Michael
  • 713
  • 10
  • 27