DylanSp
DylanSp

Reputation: 1519

"Working outside of request context" error with Celery background task

I've got a simple Python Flask/Celery app that's running into issues with flashing messages after a delay. I'm using Celery's delay() function to call a function that sleeps for 5 seconds, then flashes a message. Despite using with app.app_context() in my background function, Celery reports:

RuntimeError: Working outside of request context

I've also tried the @copy_current_request_context decorator, as mentioned by this question, but then I get

RuntimeError: This decorator can only be used at local scopes when a request context is on the stack. For instance within view functions

app.py:

from flask import Flask, flash, render_template, request
from celery import Celery
import time

app = Flask(__name__)
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'

celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)

@celery.task
def my_background_task():
    with app.app_context():
        time.sleep(5)
        flash("Background task complete.")

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        task = my_background_task.delay()
        return render_template("index.html")
    else:
        return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True,host='0.0.0.0')

templates/index.html:

<!doctype html>
{% with messages = get_flashed_messages() %}
    {% if messages %}
        <ul class=flashes>
        {% for message in messages %}
            <li>{{ message }}</li>
        {% endfor %}
        </ul>
    {% endif %}
{% endwith %}

{% block body %}
<form method="POST">
    <input type="submit" name="submit" value="Submit request">
</form>
{% endblock %}

I'm running the app with three terminal windows: running Redis with redis-server, running Celery with celery worker -A app.celery --loglevel=info, and running Python with python app.py.

Upvotes: 3

Views: 2871

Answers (1)

Luis Orduz
Luis Orduz

Reputation: 2887

The problem is that celery tasks are run by celery, they're not part of a request done by a browser or any other client so they will always be unbound since they don't know to what client they're supposed to be replying.

Running background tasks isn't really meant to interact with clients but to trigger other work (such as sending emails), unless we're using websockets or server-sent events.

Upvotes: 2

Related Questions