fix(captain/hermes): auto-react idempotente — bloqueia retry duplicate
OutgoingJob faz retry no DispatchError (até 3x ActiveJob + Sidekiq). Cada retry chamava AutoReactService.maybe_react! e criava uma reaction nova — observado em prod 02/05 quando o env var CAPTAIN_HERMES_SUBSCRIPTION_SECRET_INBOX_5 estava faltando, gerando 401 → 6 reações duplicadas no inbox EXPRESS. Adiciona guard already_reacted? que checa se já existe Message outgoing com external_source='hermes_auto_react' e in_reply_to=msg.id antes de criar uma nova. Defesa contra futuro 5xx/timeout do Hermes daemon. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3182002bd9
commit
e662913b21
@ -33,6 +33,7 @@ class Captain::Hermes::AutoReactService
|
||||
|
||||
def maybe_react!
|
||||
return unless eligible?
|
||||
return if already_reacted?
|
||||
|
||||
emoji = decide_emoji
|
||||
return if emoji.blank?
|
||||
@ -53,6 +54,16 @@ class Captain::Hermes::AutoReactService
|
||||
true
|
||||
end
|
||||
|
||||
# Evita reaction duplicada quando OutgoingJob retentar (ex: dispatch
|
||||
# retornou 401/5xx e Sidekiq reenfileirou). Sem essa guarda, cada retry
|
||||
# cria uma reaction nova e cliente vê N emojis seguidos.
|
||||
def already_reacted?
|
||||
@conversation.messages
|
||||
.where(message_type: :outgoing)
|
||||
.where("content_attributes ->> 'external_source' = ?", 'hermes_auto_react')
|
||||
.exists?(["(content_attributes ->> 'in_reply_to')::int = ?", @message.id])
|
||||
end
|
||||
|
||||
def decide_emoji
|
||||
text = @message.content.to_s.strip
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user