Celery countdown/ETA com SQS e visibility_timeout

O que aconteceu

Ao desenhar o debounce de progresso, a primeira ideia foi agendar um flush por usuário com countdown=30. Esse desenho duplicaria execuções e ainda manteria O(usuários ativos) tasks na fila — foi descartado antes de ser implementado.

Causa raiz

Com broker SQS, tasks Celery com countdown/eta são recebidas pelo worker e ficam retidas sem ack até o horário agendado. Se o atraso for maior ou igual ao visibility_timeout da fila (neste projeto: 30s, em config/celery_settings.py), o SQS reentrega a mensagem a outro worker — e a task executa duplicada.

Correção

O debounce por usuário com countdown foi substituído por flush periódico via Celery beat, lendo o estado pendente do Redis (padrão flush_pending_progress em apps/engagements/tasks.py).

Como evitar

  • Nunca usar countdown/eta ≥ visibility_timeout com broker SQS
  • Para trabalho adiado/coalescido, preferir flush periódico via Celery beat lendo estado pendente do Redis
  • Tasks que processam lotes devem terminar bem abaixo do visibility_timeout (lotes pequenos e configuráveis) e ser idempotentes, pois reentrega rara ainda é possível com CELERY_ACKS_LATE = True

Referências