- ID
- 1cac5f72-0f97-402e-a0f3-99ad5eabe528
INT-1120 — P1 Production Deploy Error: Adhoc Shuffles
Executive Summary
On 2026-05-12, a routine PROD deploy failed because an empty-string value for the
=MEMORYDB_CLUSTER_ENDPOINT_PORT= env var (set via Terraform) caused
=settings/components/common.py= to raise =ValueError= during boot, preventing
Celery workers from starting. Adhoc shuffles and other background tasks did
not process for ~2h 50m. A premature/incorrect fix was deployed at 3:50p before
the correct fix landed at 4:48p; queues recovered by 5:11p. The on-call incident
Slack workflow also failed (separate bug, since fixed). Confirmed CX impact: at
least 3 cancellations.
- *Severity:* P1 (Highest)
- *Status:* In Review (assignee: Colin Powell; reporter: Stephen Johnston)
- *Jira:* [[https://hungryroot.atlassian.net/browse/INT-1120][INT-1120]]
- *Total outage:* 2h 50m of Celery processing
- *Root cause:* Terraform-set empty string for =MEMORYDB_CLUSTER_ENDPOINT_PORT=
cast to =int()= in =common.py= → boot failure
- *Resolution:* Default-on-empty handling deployed at 4:48p; queue purged via
shell during war room
Timeline (EDT, 2026-05-12)
| Time | Event |
|-------+----------------------------------------------------------------------------------------|
| 2:21p | Initial PROD deploy started |
| 2:52p | Initial deploy errored on last few ECS tasks |
| 3:00p | Celery urgent failures begin |
| 3:38p | Root cause found: env var setting in =common.py= |
| 3:50p | First *incorrect* fix deployed |
| 4:15p | Proper fix identified |
| 4:28p | Incorrect fix re-deploy attempt; failed |
| 4:30p | War room started; incident channel *not* auto-created (on-call workflow bug) |
| 4:48p | Proper fix deployed (PRs [[https://github.com/hungryroot/hungryroot/pull/13994][#13994]], [[https://github.com/hungryroot/hungryroot/pull/13998][#13998]]) |
| 5:10p | Celery urgent recovering; shuffle queue still backlogged → purged via shell |
| 5:11p | Queues recovered; incident closed |
Impact
- ECS task rollout blocked; Celery worker fleet would not boot.
- Background processing lag/outage for ~2h 50m (adhoc shuffles, smartgrocery
queue, other tasks).
- Confirmed business impact: at least 3 customer cancellations attributed by CX.
- Secondary problem: adhoc shuffle queue couldn't drain even after fix because
retry cadence (30s) was far shorter than expiration (12h) — feedback loop kept
re-queuing faster than workers could process. Resolved by manually purging the
=smartgrocery= queue.
Root Cause
Terraform difference in =MEMORYDB_CLUSTER_ENDPOINT_PORT= setting caused an empty
string to be passed in; =django-environ= then tried =int('')= and crashed
settings load:
#+BEGIN_SRC text
File "hrplatform/settings/components/common.py", line 459, in <module>
MEMORYDB_CLUSTER_ENDPOINT_PORT = env("MEMORYDB_CLUSTER_ENDPOINT_PORT", default=6379)
...
ValueError: invalid literal for int() with base 10: ''
#+END_SRC
Open question (not caught in prior envs): why this didn't surface until PROD.
Contributing Factors
- Premature/incorrect fix deployed once, then a failed deploy attempt before the
good release.
- On-call =Report Production Incident= Slack workflow aborted because adding a
specific user (BZ) to the auto-created channel failed → rest of flow aborted.
- Adhoc shuffle retry/expiration mismatch amplified backlog after fix landed.
Resolution
- 4:48p: Correct env var default-on-empty deployed (PRs
[[https://github.com/hungryroot/hungryroot/pull/13994][#13994]], [[https://github.com/hungryroot/hungryroot/pull/13998][#13998]]).
- 5:10p: Cleared =smartgrocery= queue via shell to break the requeue feedback
loop:
#+begin_src python
from django.conf import settings
from kombu import Connection
with Connection(settings.CELERY_BROKER_URL) as conn:
count = conn.default_channel.queue_purge('smartgrocery')
print(f'Purged {count} messages from smartgrocery')
#+end_src
- 5:11p: Celery queues recovered; incident operationally closed.
Action Items
DONE
- [ ] *Root cause identified* and documented in ticket.
- [ ] *Proper fix deployed* — env var default-on-empty handling
([[https://github.com/hungryroot/hungryroot/pull/13994][PR #13994]], [[https://github.com/hungryroot/hungryroot/pull/13998][PR #13998]]).
- [ ] *Celery deploy health checks added* during incident (Jag).
- [ ] *Smartgrocery queue purged* to break requeue feedback loop.
- [ ] *On-call Slack workflow fixed* (Ellen) — was failing because BZ couldn't
be auto-added to the incident channel, which aborted the rest of the flow.
- [ ] *Follow-up PRs merged* (Jag): [[https://github.com/hungryroot/hungryroot/pull/14017][#14017]], [[https://github.com/hungryroot/hungryroot/pull/14019][#14019]].
TODO
- [ ] *Postmortem document* — exact env var, why =common.py= allowed bad state,
guardrails (tests, config validation, staged rollout).
- [ ] *Celery queue-depth alert* — no task failures fired during this incident,
just queue growth. Need an alert when Celery queues back up. (Colin)
- [ ] *Task-in-queue-time alert* — likely an anomaly check, not a static
monitor. (Colin)
- [ ] *Move existing test alerts to production* — Andrew has DD monitor
[[https://app.datadoghq.com/monitors/278415339][278415339]] in =datadog-test=; decide whether to move to on-call alerts or
build new ones.
- [ ] *Prevent rollout under Terraform drift* — investigate stopping deploys
when Terraform vars differ across tasks/services; "TODO PREVENTION" flagged
in ticket.
- [ ] *Deploy safety review* — rollback criteria and clearer
abort/rollback playbooks for partial ECS rollouts after a bad config deploy.
- [ ] *[[https://hungryroot.atlassian.net/browse/ISA-2829][ISA-2829]]* — Live ad-hoc shuffles should have expiration matching requeue
cadence. Currently 12h expiration + 30s requeue → cascading overload.
Proposals: (a) shorten =CELERY_TASK_EXPIRATION_SECONDS= or tie 30s cache
timeout to a DC; (b) match retry time and timeout, make both configurable
from our side. /Status: Ready for Testing — Jag./
References
- Jira: [[https://hungryroot.atlassian.net/browse/INT-1120][INT-1120]], linked: [[https://hungryroot.atlassian.net/browse/ISA-2829][ISA-2829]]
- PRs: [[https://github.com/hungryroot/hungryroot/pull/13994][#13994]], [[https://github.com/hungryroot/hungryroot/pull/13998][#13998]], [[https://github.com/hungryroot/hungryroot/pull/14017][#14017]], [[https://github.com/hungryroot/hungryroot/pull/14019][#14019]]
- Initial deploy run: [[https://github.com/hungryroot/hungryroot/actions/runs/25753774980/job/75639605612][actions/runs/25753774980]]
- Incorrect fix run: [[https://github.com/hungryroot/hungryroot/actions/runs/25758847709][actions/runs/25758847709]]
- Final fix run: [[https://github.com/hungryroot/hungryroot/actions/runs/25761689208][actions/runs/25761689208]]
- DD monitor (test): [[https://app.datadoghq.com/monitors/278415339][278415339]]