Flask-Celery-Tools
This is a fork of Flask-Celery-Helper
Even though the Flask documentation says Celery extensions are
unnecessary now, I found that I still need an extension to properly use Celery in large Flask applications. Specifically
I need an init_app() method to initialize Celery after I instantiate it.
This extension also comes with a single_instance method.
- Python PyPy, 3.11, 3.12 and 3.13 supported.
Attribution
Single instance decorator inspired by Ryan Roemer.
Quickstart
Install:
pip install Flask-Celery-Tools
Examples
Basic Example
# example.py
from flask import Flask
from flask_celery import Celery
app = Flask('example')
app.config['CELERY_BROKER_URL'] = 'redis://localhost'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost'
app.config['CELERY_TASK_LOCK_BACKEND'] = 'redis://localhost'
celery = Celery(app)
@celery.task()
def add_together(a: int, b: int) -> int:
return a + b
if __name__ == '__main__':
result = add_together.delay(23, 42)
print(result.get())
Run these two commands in separate terminals:
celery -A example.celery worker
python example.py
Factory Example
# extensions.py
from flask_celery import Celery
celery = Celery()
# application.py
from flask import Flask
from extensions import celery
def create_app() -> Flask:
app = Flask(__name__)
app.config['CELERY_IMPORTS'] = ('tasks.add_together', )
app.config['CELERY_BROKER_URL'] = 'redis://localhost'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost'
app.config['CELERY_TASK_LOCK_BACKEND'] = 'redis://localhost'
celery.init_app(app)
return app
# tasks.py
from extensions import celery
@celery.task()
def add_together(a: int, b: int) -> int:
return a + b
# manage.py
from application import create_app
app = create_app()
app.run()
Custom Task Base Class
You can provide your own base task class to Celery() or init_app(). It must extend celery.Task and will be used as the base for the internal FlaskTask, so Flask context injection is preserved while your custom behaviour (retry logic, logging, etc.) is inherited by all tasks.
# example.py
from celery import Task
from flask import Flask
from flask_celery import Celery
class MyBaseTask(Task):
abstract = True
def on_failure(self, exc, task_id, args, kwargs, einfo):
print(f"Task {task_id} failed: {exc}")
app = Flask('example')
app.config['CELERY_BROKER_URL'] = 'redis://localhost'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost'
celery = Celery(app, task_cls=MyBaseTask)
@celery.task()
def add_together(a: int, b: int) -> int:
return a + b
The same parameter is available on init_app() for the factory pattern. A value passed to init_app() takes precedence over one passed to Celery().
celery = Celery(task_cls=FallbackTask)
celery.init_app(app, task_cls=MyBaseTask) # MyBaseTask wins
Single Instance Example
# example.py
import time
from flask import Flask
from flask_celery import Celery, single_instance
from flask_redis import Redis
app = Flask('example')
app.config['REDIS_URL'] = 'redis://localhost'
app.config['CELERY_BROKER_URL'] = 'redis://localhost'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost'
app.config['CELERY_TASK_LOCK_BACKEND'] = 'redis://localhost'
celery = Celery(app)
Redis(app)
@celery.task(bind=True)
@single_instance
def sleep_one_second(a: int, b: int) -> int:
time.sleep(1)
return a + b
if __name__ == '__main__':
task1 = sleep_one_second.delay(23, 42)
time.sleep(0.1)
task2 = sleep_one_second.delay(20, 40)
results1 = task1.get(propagate=False)
results2 = task2.get(propagate=False)
print(results1) # 65
if isinstance(results2, Exception) and str(results2) == 'Failed to acquire lock.':
print('Another instance is already running.')
else:
print(results2) # Should not happen.
Locking backends
Flask-Celery-Tools supports multiple locking backends you can use:
Filesystem
Filesystem locking backend is using file locks on filesystem where worker is running, WARNING this backend is not usable for distributed tasks!!!
Redis
Redis backend is using redis for storing task locks, this backend is good for distributed tasks.
Database (MariaDB, PostgreSQL, etc)
Database backend is using database supported by SqlAlchemy to store task locks, this backend is good for distributed tasks. Except sqlite database that have same limitations as filesystem backend.
Release files for Flask-Celery-Tools 1.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flask_celery_tools-1.7.0.tar.gz | 14.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flask_celery_tools-1.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:29.4 kB
Release files / flask_celery_tools-1.7.0.tar.gz
| Download URL | flask_celery_tools-1.7.0.tar.gz |
|---|---|
| Size | 14.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
65f7b5026b85fd3d0ca1167c6f023bc721930d7724420e4e99d6e7f20db0a327
|
|
BLAKE2b-256 checksum How to use checksums |
9912127c8705f3eb25ab907f753c458cfb107ef18e7ecb2bd3732383479975a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / flask_celery_tools-1.7.0-py3-none-any.whl
| Download URL | flask_celery_tools-1.7.0-py3-none-any.whl |
|---|---|
| Size | 14.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
70c5b531f2a4db624dec81b0a396ce194bd6ba62ff4c94c5a14071f4f89f7413
|
|
BLAKE2b-256 checksum How to use checksums |
1f8f353f8e5d975d16ae23f7c6cd286e379e25577fae70553fb5c5b803bc5b50
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|