Skip to main content

celery-tasks

Create or modify Celery tasks and periodic task configuration. Use when: adding new background tasks, setting up periodic/scheduled tasks, configuring Celery workers, or understanding the Celery app setup.

Informações da origem

Repositório
tedivm/robs_awesome_python_template
Última atividade na origem
16 de maio de 2026 às 17:54
Idioma detectado do SKILL.md
inglês
Estrelas
312
Forks
23

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
celery-tasks
description
Create or modify Celery tasks and periodic task configuration. Use when: adding new background tasks, setting up periodic/scheduled tasks, configuring Celery workers, or understanding the Celery app setup.
# Celery Tasks > **context7**: If the `mcp_context7` tool is available, resolve and load the full `celery` documentation before making any changes to the task system: > ``` > mcp_context7_resolve-library-id: "celery" > mcp_context7_get-library-docs: <resolved-id> > ``` The Celery application is defined in `{{cookiecutter.__package_slug}}/celery.py`. Tasks are exposed via the `@celery.task` decorator. --- ## Defining Tasks Import the `celery` app instance and decorate functions: ```python from logging import getLogger from {{cookiecutter.__package_slug}}.celery import celery logger = getLogger(__name__) @celery.task def send_email(to: str, subject: str, body: str) -> dict[str, str]: """Send an email asynchronously.""" logger.info(f"Sending email to {to}: {subject}") return {"status": "sent", "to": to} ``` **Rules:** - Use `logger` (never `print`) for all output - Pass IDs, not objects — tasks serialize arguments, complex objects can't be serialized reliably - Return simple types (dict, list, primitives) — not ORM instances --- ## Task Organization Organize tasks in separate modules under `{{cookiecutter.__package_slug}}/tasks/`: ``` {{cookiecutter.__package_slug}}/ ├── celery.py # Celery app configuration └── tasks/ ├── __init__.py ├── email.py # Email-related tasks └── reports.py # Report generation tasks ``` Import task modules in `{{cookiecutter.__package_slug}}/celery.py` to ensure registration: ```python from {{cookiecutter.__package_slug}}.tasks import email, reports ``` --- ## Calling Tasks ```python # Fire and forget send_email.delay("user@example.com", "Welcome", "Thanks for signing up!") # With options send_email.apply_async( args=["user@example.com", "Welcome", "Body"], countdown=60, # Execute after 60 seconds queue='emails', # Route to specific queue ) # Get result (blocking) result = send_email.delay("user@example.com", "Hello", "Body") output = result.get(timeout=10) ``` --- ## Periodic Tasks Use the `on_after_configure` signal in `{{cookiecutter.__package_slug}}/celery.py` (Celery's documented pattern for periodic task registration): ```python from celery import Celery from celery.schedules import crontab @celery.on_after_configure.connect def setup_periodic_tasks(sender: Celery, **kwargs) -> None: logger.info("Setting up periodic tasks") sender.add_periodic_task(300.0, cleanup_old_data.s(), name="Cleanup every 5 min") sender.add_periodic_task( crontab(hour=2, minute=0), generate_report.s(), name="Daily report at 2 AM" ) ``` > **Note:** Use `on_after_finalize` instead of `on_after_configure` only when periodic tasks reference tasks defined in external modules, to ensure the task registry is fully populated before registration. --- {%- if cookiecutter.include_sqlalchemy == "y" %} ## Database Access in Tasks Use the project's `get_session` with an async context manager. Wrap async work in a single `asyncio.run()` call: ```python import asyncio from {{cookiecutter.__package_slug}}.services.db import get_session @celery.task def process_user_sync(user_id: int) -> dict[str, str]: return asyncio.run(process_user(user_id)) async def process_user(user_id: int) -> dict[str, str]: async with get_session() as session: # ... async DB operations pass return {"status": "done"} ``` > **Warning:** `asyncio.run()` creates a new event loop. It will raise `RuntimeError` if called from within an existing event loop (e.g., when using Celery's `gevent` or `eventlet` worker pool). In those cases, use `asyncio.get_event_loop().run_until_complete()` or configure Celery with the `asynpool` worker. --- {%- endif %} {%- if cookiecutter.include_aiocache == "y" %} ## Cache Integration Caches are automatically initialized on `on_after_configure`. Use them directly in tasks: ```python import asyncio from {{cookiecutter.__package_slug}}.services.cache import get_cached, set_cached @celery.task def cached_task(key: str) -> str | None: async def _run() -> str | None: value = await get_cached(key) if value is None: value = compute_expensive_value() await set_cached(key, value, alias="persistent") return value return asyncio.run(_run()) ``` > **Note:** When calling multiple async functions, batch them in a single `async def` and wrap with one `asyncio.run()` call. Calling `asyncio.run()` multiple times in the same function will raise `RuntimeError`. --- {%- endif %} ## Retries ```python from logging import getLogger logger = getLogger(__name__) @celery.task(bind=True, max_retries=3, default_retry_delay=60) def fragile_task(self) -> None: try: do_risky_thing() except Exception as exc: logger.exception("Task failed, retrying") raise self.retry(exc=exc, countdown=2 ** self.request.retries) ``` > **Note:** Always pass the caught exception to `self.retry(exc=exc)` so the original traceback is preserved in logs and raised when `max_retries` is exceeded. --- ## Style Checklist - [ ] Task uses `logger` (not `print`) for all output - [ ] Task accepts IDs, not complex objects - [ ] Task returns simple types (dict, list, primitives) - [ ] Task module is imported in `{{cookiecutter.__package_slug}}/celery.py` for registration - [ ] `@celery.task` decorator used (not standalone `@app.task`) - [ ] Async tasks use a single `asyncio.run()` wrapper (batch multiple awaits in one `async def`) - [ ] Retries use `bind=True` with `self.retry(exc=exc)` - [ ] Periodic tasks use `on_after_configure` signal (not `on_after_finalize`) --- ## Further Reading - [docs/dev/celery.md](../../docs/dev/celery.md) — Full Celery developer guide - [Celery Docs](https://docs.celeryq.dev/)
Ver no GitHub