Skip to main content

Celery tasks

Celery (EMAW_BACKEND/celery.py, app name emaw) autodiscovers tasks.py in every app. Broker and results are Redis databases /1 and /2 of REDIS_URL. Tasks ignore results, ack late, prefetch one, and have a 300 s hard / 240 s soft time limit. The request id is propagated into task logs.

Two compose services run it: worker (--concurrency=2) and beat (schedule file in /tmp, so it is rebuilt on restart). In tests Celery is eager: tasks run inline.

Beat schedule (CELERY_BEAT_SCHEDULE in settings/base.py)​

NameTaskEvery
events-fetch-meet-attendanceevents.tasks.fetch_recent_meet_attendance30 min
deposco-sync-ordersdeposco.tasks.sync_deposco_ordersDEPOSCO_SYNC_INTERVAL_MINUTES (default 30)
deposco-sync-inventorydeposco.tasks.sync_deposco_inventoryDEPOSCO_INVENTORY_SYNC_MINUTES (default 60)
deposco-sync-order-historydeposco.tasks.sync_deposco_order_history60 min

Deposco has no webhooks, so shipments, tracking, inventory and all-channel order history are polled.

Tasks by module​

ModuleTasksTriggered by
store/tasks.pysend_order_confirmation_email, send_order_shipped_email, link_order_to_contact, send_order_staff_notificationStripe webhook (paid), Deposco sync (shipped)
events/tasks.pygeocode_event, link_registration_to_contact, send_event_confirmation_email, send_guest_confirmation_email, send_overbooked_staff_notification, sync_event_meeting, send_leader_email, fetch_event_attendance, fetch_recent_meet_attendanceEvent save, webhook, staff actions, beat
donations/tasks.pylink_donation_to_contact, send_donation_receipt_email, send_donation_staff_notification, send_donation_payment_failed_notification, send_recurring_donation_cancelled_emailsStripe webhook (checkout, invoice, subscription events)
deposco/tasks.pysubmit_order_to_deposco, sync_deposco_orders, sync_deposco_inventory, sync_deposco_order_history, notify_deposco_problemWebhook (paid), beat, staff resubmit
crm/tasks.pygeocode_contact, run_geography_assignContact save / address change, bulk assignment runs (GeographyAssignRun, polled by the CRM)
campaigns/tasks.pystart_campaign, send_campaign_batch, finalize_campaign, generate_ai_template_draftSend/schedule, batch chaining, AI draft requests

The commerce flow in tasks​

Linking a buyer to the CRM replaces the contact's address with the billing address, geocodes it (geocode_contact) and re-assigns region and areas. Nothing is linked before payment.

Campaign send pipeline​

start_campaign builds the recipient list from the audience definition (respecting suppression, marketing status and the CAMPAIGN_SEND_ALLOWED_GROUP_IDS guard), then chains send_campaign_batch jobs sized by CAMPAIGN_BATCH_SIZE at CAMPAIGN_SEND_RATE_PER_MINUTE, and finalize_campaign closes it. Delivery and engagement events come back later through the ACS Event Grid webhook. Details: campaigns/README.md.

Operating​

docker compose logs -f worker
docker compose logs -f beat
docker compose exec django python -m celery -A EMAW_BACKEND inspect active
docker compose exec django python -m celery -A EMAW_BACKEND inspect scheduled

If Redis is restarted, queued tasks are lost (redis_data persists on disk but Celery queues are not the kind of thing to trust after a crash). Re-trigger from the admin app (resubmit order, resend confirmation) or management commands (deposco_submit_order, deposco_sync).