Repository: getsentry/sentry-python

Issue:
Celery integration not capturing error with max_tasks_per_child = 1
The celery integration is failing to capture the exception when I use a celery factory pattern which patches the celery task with Flask's context.

This is `web/celery_factory.py`
```
# Source: https://stackoverflow.com/questions/12044776/how-to-use-flask-sqlalchemy-in-a-celery-task

from celery import Celery
import flask


class FlaskCelery(Celery):

    def __init__(self, *args, **kwargs):
        super(FlaskCelery, self).__init__(*args, **kwargs)
        self.patch_task()

        if 'app' in kwargs:
            self.init_app(kwargs['app'])

    def patch_task(self):
        TaskBase = self.Task
        _celery = self

        class ContextTask(TaskBase):
            abstract = True

            def __call__(self, *args, **kwargs):
                if flask.has_app_context():
                    return TaskBase.__call__(self, *args, **kwargs)
                else:
                    with _celery.app.app_context():
                        return TaskBase.__call__(self, *args, **kwargs)

        self.Task = ContextTask

    def init_app(self, app):
        self.app = app
        self.config_from_object(app.config)


celery_app = FlaskCelery()
```

I am adding a random `raise` inside a simple task

```
import celery_app from celery_factory.py
@celery_app.task
def simple_task():
    raise Exception("Testing Celery exception")
```

The error I get printed is:
```
[2019-03-08 21:24:21,117: ERROR/ForkPoolWorker-31] Task simple_task[d6e959b1-7253-4e55-861d-c1968ae14e1c] raised unexpected: RuntimeError('No active exception to reraise')
Traceback (most recent call last):
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 382, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/okomarov/Documents/repos/myproject/web/celery_factory.py", line 28, in __call__
    return TaskBase.__call__(self, *args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 641, in __protected_call__
    return self.run(*args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 66, in _inner
    reraise(*_capture_exception())
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise
    raise value
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 64, in _inner
    return f(*args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 66, in _inner
    reraise(*_capture_exception())
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise
    raise value
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 64, in _inner
    return f(*args, **kwargs)
  File "/Users/okomarov/Documents/repos/myproject/web/simple_task.py", line 4, in simple_task
    raise Exception("Testing Celery exception")
RuntimeError: No active exception to reraise
```

Relevant pip packages:
```
Celery==4.2.1
Flask==1.0.2
sentry-sdk==0.7.4
```

The integration is called as following (flask integration works as expected):
```
from flask import Flask
from celery_factory import celery_app
from config import config_to_use


def create_app():
    app = Flask()
    app.config.from_object(config_to_use)

    init_logging(app)

    register_extensions(app)
    register_blueprints(app)
    register_jinja_extras(app)

    return app


def init_logging(app):
    import sentry_sdk
    from sentry_sdk.integrations.flask import FlaskIntegration
    from sentry_sdk.integrations.celery import CeleryIntegration

    sentry_sdk.init(
        dsn=app.config.get('FLASK_SENTRY_DSN'),
        integrations=[FlaskIntegration(), CeleryIntegration()]
        )

...
```


Discussion:
Could this be related to https://github.com/getsentry/sentry-python/issues/265? I've heard people downgrading the SDK to pre 0.7.0 to fix that issue.

May I ask which celery version this is?
@untitaker Thanks for gettting back. I updated the original question with the versions of flask, celery and sentry-sdk. Will test pre 0.7.0 and will get back.
So I am trying this app now, and can't repro the issue by hitting the index endpoint:

<details><summary>click</summary>

```python
import flask
from celery import Celery

import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.celery import CeleryIntegration

sentry_sdk.init(integrations=[FlaskIntegration(), CeleryIntegration()])


app = flask.Flask(__name__)


class FlaskCelery(Celery):
    def __init__(self, *args, **kwargs):
        super(FlaskCelery, self).__init__(*args, **kwargs)
        self.patch_task()

        if "app" in kwargs:
            self.init_app(kwargs["app"])

    def patch_task(self):
        TaskBase = self.Task
        _celery = self

        class ContextTask(TaskBase):
            abstract = True

            def __call__(self, *args, **kwargs):
                if flask.has_app_context():
                    return TaskBase.__call__(self, *args, **kwargs)
                else:
                    with _celery.app.app_context():
                        return TaskBase.__call__(self, *args, **kwargs)

        self.Task = ContextTask

    def init_app(self, app):
        self.app = app
        self.config_from_object(app.config)


celery_app = FlaskCelery()
celery_app.conf.broker_url = "redis://localhost:6379/0"
celery_app.init_app(app)


@celery_app.task
def simple_task():
    raise Exception("Testing Celery exception")


@app.route("/")
def index():
    simple_task.delay()

    return "oK"

```
</details>

Are you able to repro with this? It should be almost identical to what you have.

I am starting the app like this:

* `python -c 'from lolcelery import app; app.run()'`
* `celery -A lolcelery.celery_app worker`
I've tried sentry_sdk 0.6.9 and the most recent now 0.7.6. Launching app with `flask run` and celery with `celery worker -A app:celery_app`

I can see the error printed where celery is running but still nothing on sentry.io (flask errors come through, tested):
```
[2019-03-09 18:23:46,427: ERROR/ForkPoolWorker-6] Task webapp.simple_task[9b0e4aa8-16d3-4977-ba77-62af00cced84] raised unexpected: Exception('Testing Celery exception')
Traceback (most recent call last):
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 382, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/okomarov/Documents/repos/myproject/web/celery_factory.py", line 28, in __call__
    return TaskBase.__call__(self, *args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 641, in __protected_call__
    return self.run(*args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 66, in _inner
    reraise(*_capture_exception())
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise
    raise value
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 64, in _inner
    return f(*args, **kwargs)
  File "/Users/okomarov/Documents/repos/myproject/web/webapp.py", line 175, in simple_task
    raise Exception("Testing Celery exception")
Exception: Testing Celery exception
```

I will next test your setup to make sure it's not my local environment quirks.


There are some issues with initialization order in the celery integration. Concretely you should initialize the SDK when the celery app is loaded (make sure you see the output on worker startup when using `init(debug=True)`, not only when a task starts)

I thought I documented this, but apparently not: https://github.com/getsentry/sentry-docs/pull/826
There is somethinfg hairier unfortunately. So it loads the integration and even sends the info.
<details>
 <summary>Form launch to error with debug info</summary>

```
celery worker -A app:celery_app

 [sentry] DEBUG: Setting up integrations (with default = True)
 [sentry] DEBUG: Setting up previously not enabled integration flask
 [sentry] DEBUG: Setting up previously not enabled integration celery
 [sentry] DEBUG: Setting up previously not enabled integration logging
 [sentry] DEBUG: Setting up previously not enabled integration stdlib
 [sentry] DEBUG: Setting up previously not enabled integration excepthook
 [sentry] DEBUG: Setting up previously not enabled integration dedupe
 [sentry] DEBUG: Setting up previously not enabled integration atexit
 [sentry] DEBUG: Setting up previously not enabled integration modules
 [sentry] DEBUG: Setting up previously not enabled integration argv
 [sentry] DEBUG: Setting up previously not enabled integration threading
 [sentry] DEBUG: Enabling integration flask
 [sentry] DEBUG: Enabling integration celery
 [sentry] DEBUG: Enabling integration logging
 [sentry] DEBUG: Enabling integration stdlib
 [sentry] DEBUG: Enabling integration excepthook
 [sentry] DEBUG: Enabling integration dedupe
 [sentry] DEBUG: Enabling integration atexit
 [sentry] DEBUG: Enabling integration modules
 [sentry] DEBUG: Enabling integration argv
 [sentry] DEBUG: Enabling integration threading
[2019-03-09 18:46:56,469] INFO in app: Initializing database connection.
[2019-03-09 18:46:56,470] INFO in app: Initializing Celery app.
 
 -------------- celery@Olegs-MBP.local v4.2.0 (windowlicker)
---- **** ----- 
--- * ***  * -- Darwin-18.2.0-x86_64-i386-64bit 2019-03-09 18:46:59
-- * - **** --- 
- ** ---------- [config]
- ** ---------- .> app:         __main__:0x10cec5908
- ** ---------- .> transport:   redis://localhost:6379/0
- ** ---------- .> results:     redis://localhost:6379/0
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery
                

 [sentry] DEBUG: Sending error event [9823659b9f1a4f6ea3f2f5a5f3308858] to sentry.io project:1408785
[2019-03-09 18:47:43,591: DEBUG/ForkPoolWorker-5] Sending error event [9823659b9f1a4f6ea3f2f5a5f3308858] to sentry.io project:1408785
[2019-03-09 18:47:43,613: ERROR/ForkPoolWorker-5] Task webapp.simple_task[c6dc958d-3a70-4728-9399-7dece57d0c15] raised unexpected: Exception('Testing Celery exception')
Traceback (most recent call last):
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 382, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/okomarov/Documents/repos/myproject/web/celery_factory.py", line 38, in __call__
    return TaskBase.__call__(self, *args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 641, in __protected_call__
    return self.run(*args, **kwargs)
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 66, in _inner
    reraise(*_capture_exception())
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise
    raise value
  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 64, in _inner
    return f(*args, **kwargs)
  File "/Users/okomarov/Documents/repos/myproject/web/webapp.py", line 175, in simple_task
    raise Exception("Testing Celery exception")
Exception: Testing Celery exception
 [sentry] INFO: event processor (<function DedupeIntegration.setup_once.<locals>.processor at 0x10cef51e0>) dropped event ({'level': 'error', 'exception': {'values': [{'module': None, 'type': 'Exception', 'value': 'Testing Celery exception', 'mechanism': {'type': 'logging', 'handled': True}, 'stacktrace': {'frames': [{'filename': 'celery/app/trace.py', 'abs_path': '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', 'function': 'trace_task', 'module': 'celery.app.trace', 'lineno': 382, 'pre_context': ['                        request=task_request,', '                    )', '', '                # -*- TRACE -*-', '                try:'], 'context_line': '                    R = retval = fun(*args, **kwargs)', 'post_context': ['                    state = SUCCESS', '                except Reject as exc:', '                    I, R = Info(REJECTED, exc), ExceptionInfo(internal=True)', '                    state, retval = I.state, I.retval', '                    I.handle_reject(task, task_request)'], 'vars': {}}, {'filename': 'celery_factory.py', 'abs_path': '/Users/okomarov/Documents/repos/myproject/web/celery_factory.py', 'function': '__call__', 'module': 'celery_factory', 'lineno': 38, 'pre_context': ['            def __call__(self, *args, **kwargs):', '                if flask.has_app_context():', '                    return TaskBase.__call__(self, *args, **kwargs)', '                else:', '                    with _celery.app.app_context():'], 'context_line': '                        return TaskBase.__call__(self, *args, **kwargs)', 'post_context': ['', '        self.Task = ContextTask', '', '    def init_app(self, app):', '        self.app = app'], 'vars': {}}, {'filename': 'celery/app/trace.py', 'abs_path': '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', 'function': '__protected_call__', 'module': 'celery.app.trace', 'lineno': 641, 'pre_context': ['            stack = self.request_stack', '            req = stack.top', '            if req and not req._protected and \\', '                    len(stack) == 1 and not req.called_directly:', '                req._protected = 1'], 'context_line': '                return self.run(*args, **kwargs)', 'post_context': ['            return orig(self, *args, **kwargs)', '        BaseTask.__call__ = __protected_call__', '        BaseTask._stackprotected = True'], 'vars': {}}, {'filename': 'webapp.py', 'abs_path': '/Users/okomarov/Documents/repos/myproject/web/webapp.py', 'function': 'simple_task', 'module': 'webapp', 'lineno': 175, 'pre_context': ["    return render_template('operation.html', context=context)", '', '', '@celery_app.task', 'def simple_task():'], 'context_line': '    raise Exception("Testing Celery exception")', 'post_context': ['', '', '@webapp_bp.route("/celery_test/")', 'def index():', '    simple_task.delay()'], 'vars': {}}]}}]}, 'logger': 'celery.app.trace', 'logentry': {'message': 'Task %(name)s[%(id)s] %(description)s: %(exc)s', 'params': {'hostname': 'celery@Olegs-MBP.local', 'id': 'c6dc958d-3a70-4728-9399-7dece57d0c15', 'name': 'webapp.simple_task', 'exc': "Exception('Testing Celery exception')", 'traceback': 'Traceback (most recent call last):\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 382, in trace_task\n    R = retval = fun(*args, **kwargs)\n  File "/Users/okomarov/Documents/repos/myproject/web/celery_factory.py", line 38, in __call__\n    return TaskBase.__call__(self, *args, **kwargs)\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 641, in __protected_call__\n    return self.run(*args, **kwargs)\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 66, in _inner\n    reraise(*_capture_exception())\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise\n    raise value\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 64, in _inner\n    return f(*args, **kwargs)\n  File "/Users/okomarov/Documents/repos/myproject/web/webapp.py", line 175, in simple_task\n    raise Exception("Testing Celery exception")\nException: Testing Celery exception\n', 'args': '[]', 'kwargs': '{}', 'description': 'raised unexpected', 'internal': False}}, 'extra': {'stack_info': None, 'asctime': '2019-03-09 18:47:43,613'}, 'event_id': '6ce54f345d4f4267b56deb368b2332b6', 'timestamp': datetime.datetime(2019, 3, 9, 18, 47, 43, 615940), 'breadcrumbs': [{'ty': 'log', 'level': 'info', 'category': 'root', 'message': 'Initializing database connection.', 'timestamp': datetime.datetime(2019, 3, 9, 18, 46, 56, 469992), 'data': {'stack_info': None, 'asctime': '2019-03-09 18:46:56,469'}, 'type': 'default'}, {'ty': 'log', 'level': 'info', 'category': 'root', 'message': 'Initializing Celery app.', 'timestamp': datetime.datetime(2019, 3, 9, 18, 46, 56, 470213), 'data': {'stack_info': None, 'asctime': '2019-03-09 18:46:56,470'}, 'type': 'default'}]})
[2019-03-09 18:47:43,616: INFO/ForkPoolWorker-5] event processor (<function DedupeIntegration.setup_once.<locals>.processor at 0x10cef51e0>) dropped event ({'level': 'error', 'exception': {'values': [{'module': None, 'type': 'Exception', 'value': 'Testing Celery exception', 'mechanism': {'type': 'logging', 'handled': True}, 'stacktrace': {'frames': [{'filename': 'celery/app/trace.py', 'abs_path': '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', 'function': 'trace_task', 'module': 'celery.app.trace', 'lineno': 382, 'pre_context': ['                        request=task_request,', '                    )', '', '                # -*- TRACE -*-', '                try:'], 'context_line': '                    R = retval = fun(*args, **kwargs)', 'post_context': ['                    state = SUCCESS', '                except Reject as exc:', '                    I, R = Info(REJECTED, exc), ExceptionInfo(internal=True)', '                    state, retval = I.state, I.retval', '                    I.handle_reject(task, task_request)'], 'vars': {}}, {'filename': 'celery_factory.py', 'abs_path': '/Users/okomarov/Documents/repos/myproject/web/celery_factory.py', 'function': '__call__', 'module': 'celery_factory', 'lineno': 38, 'pre_context': ['            def __call__(self, *args, **kwargs):', '                if flask.has_app_context():', '                    return TaskBase.__call__(self, *args, **kwargs)', '                else:', '                    with _celery.app.app_context():'], 'context_line': '                        return TaskBase.__call__(self, *args, **kwargs)', 'post_context': ['', '        self.Task = ContextTask', '', '    def init_app(self, app):', '        self.app = app'], 'vars': {}}, {'filename': 'celery/app/trace.py', 'abs_path': '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', 'function': '__protected_call__', 'module': 'celery.app.trace', 'lineno': 641, 'pre_context': ['            stack = self.request_stack', '            req = stack.top', '            if req and not req._protected and \\', '                    len(stack) == 1 and not req.called_directly:', '                req._protected = 1'], 'context_line': '                return self.run(*args, **kwargs)', 'post_context': ['            return orig(self, *args, **kwargs)', '        BaseTask.__call__ = __protected_call__', '        BaseTask._stackprotected = True'], 'vars': {}}, {'filename': 'webapp.py', 'abs_path': '/Users/okomarov/Documents/repos/myproject/web/webapp.py', 'function': 'simple_task', 'module': 'webapp', 'lineno': 175, 'pre_context': ["    return render_template('operation.html', context=context)", '', '', '@celery_app.task', 'def simple_task():'], 'context_line': '    raise Exception("Testing Celery exception")', 'post_context': ['', '', '@webapp_bp.route("/celery_test/")', 'def index():', '    simple_task.delay()'], 'vars': {}}]}}]}, 'logger': 'celery.app.trace', 'logentry': {'message': 'Task %(name)s[%(id)s] %(description)s: %(exc)s', 'params': {'hostname': 'celery@Olegs-MBP.local', 'id': 'c6dc958d-3a70-4728-9399-7dece57d0c15', 'name': 'webapp.simple_task', 'exc': "Exception('Testing Celery exception')", 'traceback': 'Traceback (most recent call last):\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 382, in trace_task\n    R = retval = fun(*args, **kwargs)\n  File "/Users/okomarov/Documents/repos/myproject/web/celery_factory.py", line 38, in __call__\n    return TaskBase.__call__(self, *args, **kwargs)\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py", line 641, in __protected_call__\n    return self.run(*args, **kwargs)\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 66, in _inner\n    reraise(*_capture_exception())\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise\n    raise value\n  File "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 64, in _inner\n    return f(*args, **kwargs)\n  File "/Users/okomarov/Documents/repos/myproject/web/webapp.py", line 175, in simple_task\n    raise Exception("Testing Celery exception")\nException: Testing Celery exception\n', 'args': '[]', 'kwargs': '{}', 'description': 'raised unexpected', 'internal': False}}, 'extra': {'stack_info': None, 'asctime': '2019-03-09 18:47:43,613'}, 'event_id': '6ce54f345d4f4267b56deb368b2332b6', 'timestamp': datetime.datetime(2019, 3, 9, 18, 47, 43, 615940), 'breadcrumbs': [{'ty': 'log', 'level': 'info', 'category': 'root', 'message': 'Initializing database connection.', 'timestamp': datetime.datetime(2019, 3, 9, 18, 46, 56, 469992), 'data': {'stack_info': None, 'asctime': '2019-03-09 18:46:56,469'}, 'type': 'default'}, {'ty': 'log', 'level': 'info', 'category': 'root', 'message': 'Initializing Celery app.', 'timestamp': datetime.datetime(2019, 3, 9, 18, 46, 56, 470213), 'data': {'stack_info': None, 'asctime': '2019-03-09 18:46:56,470'}, 'type': 'default'}]})
```

</details>

@okomarov is this now referring to your own webapp or the repro case I wrote?
Still my case. Im wondering why the event has been dropped. Maybe I need to format the error message a bit better. On my phone so will try your case tomorrow.

Thanks again for the support so far! 
if you are talking about the literal message "event has been dropped", this
is expected. We capture the same exception twice (this is just a thing that
happens sometimes when you hook into so many things), so the error is
deduplicated later.

On Sat, Mar 9, 2019 at 10:40 PM Oleg Komarov <notifications@github.com>
wrote:

> Still my case. Im wondering why the event has been dropped. Maybe I need
> to format the error message a bit better. On my phone so will try your case
> tomorrow.
>
> Thanks again for the support so far!
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/getsentry/sentry-python/issues/285#issuecomment-471224571>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAzHxRJAbgQytfHr5ndedCS9BHTSX9gBks5vVCphgaJpZM4bmLnZ>
> .
>

@untitaker I tried your setup and it works as expected. Comparing your setup versus mine from the debug message, the only differences I see are:
* breadcrumbs - they don't get filtered out in my setup
* my celery app is in a separate file from the views/app

<details><summary>Sentry info: my setup</summary>

```json
{
  "level": "error",
  "exception": {
    "values": [{
      "module": "None",
      "type": "Exception",
      "value": "Testing Celery exception",
      "mechanism": {
        "type": "logging",
        "handled": "True"
      },
      "stacktrace": {
        "frames": [{
          "filename": "celery/app/trace.py",
          "abs_path": "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py",
          "function": "trace_task",
          "module": "celery.app.trace",
          "lineno": 382,
          "pre_context": ["                        request=task_request,", "                    )", "", "                # -*- TRACE -*-", "                try:"],
          "context_line": "                    R = retval = fun(*args, **kwargs)",
          "post_context": ["                    state = SUCCESS", "                except Reject as exc:", "                    I, R = Info(REJECTED, exc), ExceptionInfo(internal=True)", "                    state, retval = I.state, I.retval", "                    I.handle_reject(task, task_request)"],
          "vars": {}
        }, {
          "filename": "celery_factory.py",
          "abs_path": "/Users/okomarov/Documents/repos/myproject/web/celery_factory.py",
          "function": "__call__",
          "module": "celery_factory",
          "lineno": 28,
          "pre_context": ["            def __call__(self, *args, **kwargs):", "                if flask.has_app_context():", "                    return TaskBase.__call__(self, *args, **kwargs)", "                else:", "                    with _celery.app.app_context():"],
          "context_line": "                        return TaskBase.__call__(self, *args, **kwargs)",
          "post_context": ["", "        self.Task = ContextTask", "", "    def init_app(self, app):", "        self.app = app"],
          "vars": {}
        }, {
          "filename": "celery/app/trace.py",
          "abs_path": "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py",
          "function": "__protected_call__",
          "module": "celery.app.trace",
          "lineno": 641,
          "pre_context": ["            stack = self.request_stack", "            req = stack.top", "            if req and not req._protected and \\", "                    len(stack) == 1 and not req.called_directly:", "                req._protected = 1"],
          "context_line": "                return self.run(*args, **kwargs)",
          "post_context": ["            return orig(self, *args, **kwargs)", "        BaseTask.__call__ = __protected_call__", "        BaseTask._stackprotected = True"],
          "vars": {}
        }, {
          "filename": "webapp.py",
          "abs_path": "/Users/okomarov/Documents/repos/myproject/web/webapp.py",
          "function": "simple_task",
          "module": "webapp",
          "lineno": 175,
          "pre_context": ["    return render_template('operation.html', context=context)", "", "", "@celery_app.task", "def simple_task():"],
          "context_line": "    raise Exception('Testing Celery exception')",
          "post_context": ["", "", "@webapp_bp.route('/celery_test/')", "def index():", "    simple_task.delay()"],
          "vars": {}
        }]
      }
    }]
  },
  "logger": "celery.app.trace",
  "logentry": {
    "message": "Task %(name)s[%(id)s] %(description)s: %(exc)s",
    "params": {
      "hostname": "celery@Olegs-MBP.local",
      "id": "14d947b0-7c56-4417-8c61-e11f98d59421",
      "name": "webapp.simple_task",
      "exc": "Exception('Testing Celery exception')",
      "traceback": "Traceback (most recent call last):\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', line 382, in trace_task\n    R = retval = fun(*args, **kwargs)\n  File '/Users/okomarov/Documents/repos/myproject/web/celery_factory.py', line 28, in __call__\n    return TaskBase.__call__(self, *args, **kwargs)\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', line 641, in __protected_call__\n    return self.run(*args, **kwargs)\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py', line 66, in _inner\n    reraise(*_capture_exception())\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py', line 52, in reraise\n    raise value\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py', line 64, in _inner\n    return f(*args, **kwargs)\n  File '/Users/okomarov/Documents/repos/myproject/web/webapp.py', line 175, in simple_task\n    raise Exception('Testing Celery exception')\nException: Testing Celery exception\n",
      "args": "[]",
      "kwargs": "{}",
      "description": "raised unexpected",
      "internal": "False"
    }
  },
  "extra": {
    "stack_info": "None",
    "asctime": "2019-03-11 10:38:50,177"
  },
  "event_id": "172381d940ad481eb9ce37278126883b",
  "timestamp": "datetime.datetime(2019, 3, 11, 10, 38, 50, 179112)",
  "breadcrumbs": [{
    "ty": "log",
    "level": "info",
    "category": "root",
    "message": "Initializing database connection.",
    "timestamp": "datetime.datetime(2019, 3, 11, 10, 38, 36, 957407)",
    "data": {
      "stack_info": "None",
      "asctime": "2019-03-11 10:38:36,957"
    },
    "type": "default"
  }, {
    "ty": "log",
    "level": "info",
    "category": "root",
    "message": "Initializing Celery app.",
    "timestamp": "datetime.datetime(2019, 3, 11, 10, 38, 36, 957610)",
    "data": {
      "stack_info": "None",
      "asctime": "2019-03-11 10:38:36,957"
    },
    "type": "default"
  }]
}
```

</details>


<details>
<summary>Sentry info: single file setup</summary>

```json
{
  "level": "error",
  "exception": {
    "values": [{
      "module": "None",
      "type": "Exception",
      "value": "Testing Celery exception",
      "mechanism": {
        "type": "logging",
        "handled": "True"
      },
      "stacktrace": {
        "frames": [{
          "filename": "celery/app/trace.py",
          "abs_path": "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py",
          "function": "trace_task",
          "module": "celery.app.trace",
          "lineno": 382,
          "pre_context": ["                        request=task_request,", "                    )", "", "                # -*- TRACE -*-", "                try:"],
          "context_line": "                    R = retval = fun(*args, **kwargs)",
          "post_context": ["                    state = SUCCESS", "                except Reject as exc:", "                    I, R = Info(REJECTED, exc), ExceptionInfo(internal=True)", "                    state, retval = I.state, I.retval", "                    I.handle_reject(task, task_request)"],
          "vars": {}
        }, {
          "filename": "app.py",
          "abs_path": "/Users/okomarov/Documents/repos/myproject/web/app.py",
          "function": "__call__",
          "module": "app",
          "lineno": 33,
          "pre_context": ["            def __call__(self, *args, **kwargs):", "                if flask.has_app_context():", "                    return TaskBase.__call__(self, *args, **kwargs)", "                else:", "                    with _celery.app.app_context():"],
          "context_line": "                        return TaskBase.__call__(self, *args, **kwargs)",
          "post_context": ["", "        self.Task = ContextTask", "", "    def init_app(self, app):", "        self.app = app"],
          "vars": {}
        }, {
          "filename": "celery/app/trace.py",
          "abs_path": "/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py",
          "function": "__protected_call__",
          "module": "celery.app.trace",
          "lineno": 641,
          "pre_context": ["            stack = self.request_stack", "            req = stack.top", "            if req and not req._protected and \\", "                    len(stack) == 1 and not req.called_directly:", "                req._protected = 1"],
          "context_line": "                return self.run(*args, **kwargs)",
          "post_context": ["            return orig(self, *args, **kwargs)", "        BaseTask.__call__ = __protected_call__", "        BaseTask._stackprotected = True"],
          "vars": {}
        }, {
          "filename": "app.py",
          "abs_path": "/Users/okomarov/Documents/repos/myproject/web/app.py",
          "function": "simple_task",
          "module": "app",
          "lineno": 51,
          "pre_context": ["webapp_bp = Blueprint('webapp', __name__)", "", "", "@celery_app.task", "def simple_task():"],
          "context_line": "    raise Exception('Testing Celery exception')",
          "post_context": ["", "", "@webapp_bp.route('/')", "def index():", "    simple_task.delay()"],
          "vars": {}
        }]
      }
    }]
  },
  "logger": "celery.app.trace",
  "logentry": {
    "message": "Task %(name)s[%(id)s] %(description)s: %(exc)s",
    "params": {
      "hostname": "celery@Olegs-MBP.local",
      "id": "aaf821b2-b6f3-4c68-baf8-65d9dae7eb21",
      "name": "app.simple_task",
      "exc": "Exception('Testing Celery exception')",
      "traceback": "Traceback (most recent call last):\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', line 382, in trace_task\n    R = retval = fun(*args, **kwargs)\n  File '/Users/okomarov/Documents/repos/myproject/web/app.py', line 33, in __call__\n    return TaskBase.__call__(self, *args, **kwargs)\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/celery/app/trace.py', line 641, in __protected_call__\n    return self.run(*args, **kwargs)\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py', line 66, in _inner\n    reraise(*_capture_exception())\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/_compat.py', line 52, in reraise\n    raise value\n  File '/Users/okomarov/.virtualenvs/myenv/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py', line 64, in _inner\n    return f(*args, **kwargs)\n  File '/Users/okomarov/Documents/repos/myproject/web/app.py', line 51, in simple_task\n    raise Exception('Testing Celery exception')\nException: Testing Celery exception\n",
      "args": "[]",
      "kwargs": "{}",
      "description": "raised unexpected",
      "internal": "False"
    }
  },
  "extra": {
    "stack_info": "None",
    "asctime": "2019-03-11 10:57:53,095"
  },
  "event_id": "2c138005a9524b2b9b518a311d7732ba",
  "timestamp": "datetime.datetime(2019, 3, 11, 10, 57, 53, 98149)",
  "breadcrumbs": []
}
```

</details>

<details><summary>Single file app</summary>

```python
from celery import Celery
import flask
from flask import Blueprint
import sentry_sdk
from sentry_sdk.integrations.celery import CeleryIntegration
from sentry_sdk.integrations.flask import FlaskIntegration

sentry_sdk.init(dsn='...', integrations=[FlaskIntegration(), CeleryIntegration()], debug=True)
app = flask.Flask(__name__)


class FlaskCelery(Celery):

    def __init__(self, *args, **kwargs):
        super(FlaskCelery, self).__init__(*args, **kwargs)
        self.patch_task()

        if 'app' in kwargs:
            self.init_app(kwargs['app'])

    def patch_task(self):
        TaskBase = self.Task
        _celery = self

        class ContextTask(TaskBase):
            abstract = True

            def __call__(self, *args, **kwargs):
                if flask.has_app_context():
                    return TaskBase.__call__(self, *args, **kwargs)
                else:
                    with _celery.app.app_context():
                        return TaskBase.__call__(self, *args, **kwargs)

        self.Task = ContextTask

    def init_app(self, app):
        self.app = app
        self.config_from_object(app.config)


celery_app = FlaskCelery()
celery_app.conf.broker_url = "redis://localhost:6379/0"
celery_app.init_app(app)

webapp_bp = Blueprint('webapp', __name__)


@celery_app.task
def simple_task():
    raise Exception("Testing Celery exception")


@webapp_bp.route("/")
def index():
    simple_task.delay()

    return "oK"


app.register_blueprint(webapp_bp)
```

</details>

(I tried to fix your collapsible thin- ah, you fixed it)

Yeah. I don't see how those things are significant :(
Could you kindly point me where in the code of the python sentry_sdk the event is posted to the dsn?
I will check if the error is actually posted and how. 
If you're just looking for a place to put print statements into, this is the way to go: https://github.com/getsentry/sentry-python/blob/5cfd1f7d101f100d864e7e1e330c4bf53f5c04f2/sentry_sdk/transport.py#L94

However, you already have the output of that log stmt in your logfile.
Thanks a lot for the pointer. Yes, I will be printing and checking that the json is properly formatted etc...
If the message is being sent, but does not appear in sentry.io/issues, I guess my next best guess is to contact sentry.io/help to understand what the issue is? 

PS. We don't have any inbound filters.


I think a reasonable approach to investigating this issue now would be to take a copy your app and continuously remove random code while checking if the issue still persists. At some point there should be a repro case left that is so small there are no significant issues with intellectual property.

This is a daunting task but it's the way I've found those kind of issues in the past, at least when proprietary code is involved.
@untitaker So I managed to reproduce the issue. 
When you set the `CELERYD_MAX_TASKS_PER_CHILD = 1`, and the task errors, it hangs until you close shutdown the workers.

Let me know if you experience the same now. Also, I believe this is potentially a celery issue?

Logged an issue with celery: https://github.com/celery/celery/issues/5388
@okomarov Fantastic, I can reproduce the issue. I consider this to be a bug in the SDK and not Celery. Please close the celery issue.

This is likely a duplicate of #291. The testcase can be simplified as follows:

```python
from celery import Celery
import sentry_sdk
from sentry_sdk.integrations.celery import CeleryIntegration

sentry_sdk.init(
    "https://7a9d104a2a71477ba45654a9b350e98d@sentry.io/1288081",
    integrations=[CeleryIntegration()],
    debug=True
)

celery_app = Celery()
celery_app.conf.broker_url = "redis://localhost:6379/0"
celery_app.conf.worker_max_tasks_per_child = 1

@celery_app.task
def simple_task():
    sentry_sdk.capture_exception(Exception("Testing Celery exception"))
    # import time  # uncomment to "fix"
    # time.sleep(4)
```

At first glance this issue seems low-priority to me, since I consider bumping `max_tasks_per_child` an adequate workaround. However, I might be wrong. I wonder why you set it to that value in the first place?
@untitaker Thanks for looking into this further.

Unfortunately we have a dependency that requires the `max_tasks_per_child=1` (e.g. https://stackoverflow.com/questions/49347506/django-celery-scrapy-twisted-reactorreactornotrestartable-and-databasessl).

I tried your test case and I cannot reproduce the issue with that. I start celery with `celery worker -A app:celery_app` and after that I start a python shell, import simple task and call it. While the call seems blocking (I need to press ENTER to release), the sentry message comes through straight away. 
This happens for any value of tasks per child and without that setting altogether. 
What happens if you wrap your celery tasks with this decorator? https://docs.sentry.io/platforms/python/serverless/

(ignore that it's for serverless)
@untitaker Tested and it works both in local and production!

Adding the decorator to the patched task allows to use the usual Celery's `@app.task` without the need to stack decorators.

```
from celery import Celery
import flask
from sentry_sdk.integrations.serverless import serverless_function


class FlaskCelery(Celery):

    def __init__(self, *args, **kwargs):
        super(FlaskCelery, self).__init__(*args, **kwargs)
        self.patch_task()

        if 'app' in kwargs:
            self.init_app(kwargs['app'])

    def patch_task(self):
        TaskBase = self.Task
        _celery = self

        class ContextTask(TaskBase):
            abstract = True

            # The serverless patching is necessary with max_tasks_per_child = 1
            # See https://github.com/getsentry/sentry-python/issues/285 
            @serverless_function
            def __call__(self, *args, **kwargs):
                if flask.has_app_context():
                    return TaskBase.__call__(self, *args, **kwargs)
                else:
                    with _celery.app.app_context():
                        return TaskBase.__call__(self, *args, **kwargs)

        self.Task = ContextTask

    def init_app(self, app):
        self.app = app
        self.config_from_object(app.config)
```
Okay. This is the same as #291 but I underestimated how strongly billard diverged. So this will be a celery-specific fix.

Resolving patch:
diff --git a/sentry_sdk/integrations/celery.py b/sentry_sdk/integrations/celery.py
--- a/sentry_sdk/integrations/celery.py
+++ b/sentry_sdk/integrations/celery.py
@@ -23,12 +23,14 @@ def setup_once():
         def sentry_build_tracer(name, task, *args, **kwargs):
             # Need to patch both methods because older celery sometimes
             # short-circuits to task.run if it thinks it's safe.
-            task.__call__ = _wrap_task_call(task.__call__)
-            task.run = _wrap_task_call(task.run)
+            task.__call__ = _wrap_task_call(task, task.__call__)
+            task.run = _wrap_task_call(task, task.run)
             return _wrap_tracer(task, old_build_tracer(name, task, *args, **kwargs))
 
         trace.build_tracer = sentry_build_tracer
 
+        _patch_worker_exit()
+
         # This logger logs every status of every task that ran on the worker.
         # Meaning that every task's breadcrumbs are full of stuff like "Task
         # <foo> raised unexpected <bar>".
@@ -56,14 +58,17 @@ def _inner(*args, **kwargs):
     return _inner
 
 
-def _wrap_task_call(f):
+def _wrap_task_call(task, f):
     # Need to wrap task call because the exception is caught before we get to
     # see it. Also celery's reported stacktrace is untrustworthy.
     def _inner(*args, **kwargs):
         try:
             return f(*args, **kwargs)
         except Exception:
-            reraise(*_capture_exception())
+            exc_info = sys.exc_info()
+            with capture_internal_exceptions():
+                _capture_exception(task, exc_info)
+            reraise(*exc_info)
 
     return _inner
 
@@ -82,15 +87,6 @@ def event_processor(event, hint):
             }
 
         if "exc_info" in hint:
-            with capture_internal_exceptions():
-                if isinstance(hint["exc_info"][1], Retry):
-                    return None
-
-                if hasattr(task, "throws") and isinstance(
-                    hint["exc_info"][1], task.throws
-                ):
-                    return None
-
             with capture_internal_exceptions():
                 if issubclass(hint["exc_info"][0], SoftTimeLimitExceeded):
                     event["fingerprint"] = [
@@ -104,16 +100,39 @@ def event_processor(event, hint):
     return event_processor
 
 
-def _capture_exception():
+def _capture_exception(task, exc_info):
     hub = Hub.current
-    exc_info = sys.exc_info()
 
-    if hub.get_integration(CeleryIntegration) is not None:
-        event, hint = event_from_exception(
-            exc_info,
-            client_options=hub.client.options,
-            mechanism={"type": "celery", "handled": False},
-        )
-        hub.capture_event(event, hint=hint)
+    if hub.get_integration(CeleryIntegration) is None:
+        return
+    if isinstance(exc_info[1], Retry):
+        return
+    if hasattr(task, "throws") and isinstance(exc_info[1], task.throws):
+        return
+
+    event, hint = event_from_exception(
+        exc_info,
+        client_options=hub.client.options,
+        mechanism={"type": "celery", "handled": False},
+    )
+
+    hub.capture_event(event, hint=hint)
+
+
+def _patch_worker_exit():
+    # Need to flush queue before worker shutdown because a crashing worker will
+    # call os._exit
+    from billiard.pool import Worker  # type: ignore
+
+    old_workloop = Worker.workloop
+
+    def sentry_workloop(*args, **kwargs):
+        try:
+            return old_workloop(*args, **kwargs)
+        finally:
+            with capture_internal_exceptions():
+                hub = Hub.current
+                if hub.get_integration(CeleryIntegration) is not None:
+                    hub.flush()
 
-    return exc_info
+    Worker.workloop = sentry_workloop


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -118,3 +118,41 @@ def append(event):
         return events
 
     return inner
+
+
+@pytest.fixture
+def capture_events_forksafe(monkeypatch):
+    def inner():
+        events_r, events_w = os.pipe()
+        events_r = os.fdopen(events_r, "rb", 0)
+        events_w = os.fdopen(events_w, "wb", 0)
+
+        test_client = sentry_sdk.Hub.current.client
+
+        old_capture_event = test_client.transport.capture_event
+
+        def append(event):
+            events_w.write(json.dumps(event).encode("utf-8"))
+            events_w.write(b"\n")
+            return old_capture_event(event)
+
+        def flush(timeout=None, callback=None):
+            events_w.write(b"flush\n")
+
+        monkeypatch.setattr(test_client.transport, "capture_event", append)
+        monkeypatch.setattr(test_client, "flush", flush)
+
+        return EventStreamReader(events_r)
+
+    return inner
+
+
+class EventStreamReader(object):
+    def __init__(self, file):
+        self.file = file
+
+    def read_event(self):
+        return json.loads(self.file.readline().decode("utf-8"))
+
+    def read_flush(self):
+        assert self.file.readline() == b"flush\n"
diff --git a/tests/integrations/celery/test_celery.py b/tests/integrations/celery/test_celery.py
--- a/tests/integrations/celery/test_celery.py
+++ b/tests/integrations/celery/test_celery.py
@@ -1,3 +1,5 @@
+import threading
+
 import pytest
 
 pytest.importorskip("celery")
@@ -6,6 +8,7 @@
 from sentry_sdk.integrations.celery import CeleryIntegration
 
 from celery import Celery, VERSION
+from celery.bin import worker
 
 
 @pytest.fixture
@@ -22,7 +25,10 @@ def init_celery(sentry_init):
     def inner():
         sentry_init(integrations=[CeleryIntegration()])
         celery = Celery(__name__)
-        celery.conf.CELERY_ALWAYS_EAGER = True
+        if VERSION < (4,):
+            celery.conf.CELERY_ALWAYS_EAGER = True
+        else:
+            celery.conf.task_always_eager = True
         return celery
 
     return inner
@@ -92,11 +98,11 @@ def dummy_task(x, y):
         stack_lengths.append(len(Hub.current._stack))
         return x / y
 
-    try:
+    if VERSION >= (4,):
         dummy_task.delay(2, 2)
-    except ZeroDivisionError:
-        if VERSION >= (4,):
-            raise
+    else:
+        with pytest.raises(ZeroDivisionError):
+            dummy_task.delay(2, 2)
 
     assert len(Hub.current._stack) == 1
     if VERSION < (4,):
@@ -139,3 +145,41 @@ def dummy_task(self):
 
     for e in exceptions:
         assert e["type"] == "ZeroDivisionError"
+
+
+@pytest.mark.skipif(VERSION < (4,), reason="in-memory backend broken")
+def test_transport_shutdown(request, celery, capture_events_forksafe, tmpdir):
+    events = capture_events_forksafe()
+
+    celery.conf.worker_max_tasks_per_child = 1
+    celery.conf.broker_url = "memory://localhost/"
+    celery.conf.broker_backend = "memory"
+    celery.conf.result_backend = "file://{}".format(tmpdir.mkdir("celery-results"))
+    celery.conf.task_always_eager = False
+
+    runs = []
+
+    @celery.task(name="dummy_task", bind=True)
+    def dummy_task(self):
+        runs.append(1)
+        1 / 0
+
+    res = dummy_task.delay()
+
+    w = worker.worker(app=celery)
+    t = threading.Thread(target=w.run)
+    t.daemon = True
+    t.start()
+
+    with pytest.raises(Exception):
+        # Celery 4.1 raises a gibberish exception
+        res.wait()
+
+    event = events.read_event()
+    exception, = event["exception"]["values"]
+    assert exception["type"] == "ZeroDivisionError"
+
+    events.read_flush()
+
+    # if this is nonempty, the worker never really forked
+    assert not runs
diff --git a/tests/integrations/rq/test_rq.py b/tests/integrations/rq/test_rq.py
--- a/tests/integrations/rq/test_rq.py
+++ b/tests/integrations/rq/test_rq.py
@@ -1,13 +1,8 @@
 from sentry_sdk.integrations.rq import RqIntegration
 
-import os
-import json
-
 from fakeredis import FakeStrictRedis
 import rq
 
-from sentry_sdk import Hub
-
 
 def crashing_job(foo):
     1 / 0
@@ -40,22 +35,10 @@ def test_basic(sentry_init, capture_events):
     }
 
 
-def test_transport_shutdown(sentry_init):
+def test_transport_shutdown(sentry_init, capture_events_forksafe):
     sentry_init(integrations=[RqIntegration()])
 
-    events_r, events_w = os.pipe()
-    events_r = os.fdopen(events_r, "rb", 0)
-    events_w = os.fdopen(events_w, "wb", 0)
-
-    def capture_event(event):
-        events_w.write(json.dumps(event).encode("utf-8"))
-        events_w.write(b"\n")
-
-    def flush(timeout=None, callback=None):
-        events_w.write(b"flush\n")
-
-    Hub.current.client.transport.capture_event = capture_event
-    Hub.current.client.flush = flush
+    events = capture_events_forksafe()
 
     queue = rq.Queue(connection=FakeStrictRedis())
     worker = rq.Worker([queue], connection=queue.connection)
@@ -63,9 +46,8 @@ def flush(timeout=None, callback=None):
     queue.enqueue(crashing_job, foo=42)
     worker.work(burst=True)
 
-    event = events_r.readline()
-    event = json.loads(event.decode("utf-8"))
+    event = events.read_event()
+    events.read_flush()
+
     exception, = event["exception"]["values"]
     assert exception["type"] == "ZeroDivisionError"
-
-    assert events_r.readline() == b"flush\n"