Skip to content

Celery task errors never reach ADMINS email — metadata-fetch failures were silent for a month #293

Description

@mithro

Summary

do_revision_fetch failed every 5 minutes from 2026-06-03 to 2026-07-09 (the gf180mcu-precheck PDK_TAGPDK_COMMIT incident) and no admin ever got an email, even though ADMINS is configured and prod LOGGING has an AdminEmailHandler. The failures were only visible as raw sha256:... digests on the check-status pages.

Where the errors actually go

Celery workers run with --logfile=${LOGS_DIRECTORY}/worker.log (deployment/systemd/django-celery-http-ro-metadata.service:27), and Celery's default root-logger hijack sends everything there — e.g. /var/log/platform.wafer.space-celery-http-ro-metadata/worker.log. The logger.exception(...) tracebacks from wafer_space/projects/tasks_revisions.py:91 have been landing in that file every ~5 minutes, unseen.

Why no admin email (three independent gaps)

  1. mail_admins is only wired to request loggers. In config/settings/prod.py:138-149 the AdminEmailHandler is attached to django.request and django.security.DisallowedHost only. App loggers (wafer_space.*) propagate to root, and root has just console (prod.py:137). Celery task code can never emit to django.request. No Sentry configured either.
  2. The error path isn't even a task failure. do_revision_fetch catches the ValueError and returns an error dict (wafer_space/projects/tasks_revisions.py:90-92), so Celery records SUCCESS. Failure-based alerting would not have fired for this bug class.
  3. Celery 5 has no built-in error emails. CELERY_SEND_TASK_ERROR_EMAILS was removed in Celery 5, so exhausted-retry failures (e.g. the RequestException path after 3 retries) are also silent.

Recommended fix

  • Route app errors to email: add a wafer_space logger (or extend root) with "handlers": ["mail_admins"] at ERROR level in prod/stage LOGGING.
  • Prerequisite: fix the revisions_needs_fetching infinite requeue first (old, immutable digests still fail every 5 minutes — see the PDK incident), otherwise this change generates ~288 identical emails/day. Options: save partial metadata instead of discarding on missing pdk_version, parse PDK_COMMIT as a Makefile fallback, and/or set a failure marker so permanently-broken digests stop being requeued.
  • Complement: a Celery task_failure signal handler that mails admins (rate-limited), covering genuine task crashes that logging-based routing can miss.
  • Consider whether tasks should stop swallowing fatal errors into success-shaped return dicts — a repeated, permanent failure that reports SUCCESS defeats both alerting layers.

Acceptance criteria

  • An unhandled exception or logger.error/logger.exception in any Celery task in prod results in an ADMINS email (deduplicated/rate-limited to something sane).
  • A permanently-failing periodic fetch is surfaced once, not re-attempted every 5 minutes forever.

Context: the June incident itself is mitigated (GHCR images relabeled 2026-07-09; wafer-space/gf180mcu-precheck#45 prevents recurrence), but old check digests still fail metadata fetch every 5 minutes until the requeue fix lands.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KMV2xQm2RP5JiTzU22U1sJ

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendBackend/Django developmentbugSomething isn't workinginfrastructureDevOps and deployment

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions