Skip to content

Clear AI messages abandoned in processing - #5071

Open
elias-ba wants to merge 1 commit into
timeout-failure-taxonomyfrom
timeout-stuck-message-reaper
Open

Clear AI messages abandoned in processing#5071
elias-ba wants to merge 1 commit into
timeout-failure-taxonomyfrom
timeout-stuck-message-reaper

Conversation

@elias-ba

@elias-ba elias-ba commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Description

Even with the lifecycle fix, a message can still be stranded: the node goes away mid-answer, or a job dies in a way nothing gets to observe. The row stays :processing and the panel spins until someone reloads.

A cron worker sweeps them. It reads the candidate messages first and the live Oban job ids second, so a job that starts between the two reads is treated as alive rather than reaped. The update is guarded on status == :processing, so a message that finished in the gap is left alone.

There's a partial index on the processing rows, since that's the only slice the sweep looks at.

Closes #__

Validation steps

  1. mix test test/lightning/ai_assistant/stuck_message_reaper_test.exs
  2. Set a message to :processing with an old processing_started_at and no Oban job, run Lightning.AiAssistant.StuckMessageReaper.perform(%Oban.Job{}), and check it moves to :error and the session gets told.

AI Usage

  • I have used Claude Code

Pre-submission checklist

  • I have performed an AI review of my code
  • I have updated the changelog. (for the whole stack, in #5074)
  • I have ticked a box in "AI usage" in this PR

@github-project-automation github-project-automation Bot moved this to New Issues in Core Aug 15, 2026
@github-actions

Copy link
Copy Markdown

Security Review ✅

  • S0 (project scoping): Reaper is a system-wide background worker, not a user-facing endpoint; its broadcast targets ai_session:{id}, joined only after authorize_session_access in lib/lightning_web/channels/ai_assistant_channel.ex:39.
  • S1 (authorization): N/A — no new user-facing actions; changes are internal to Oban worker/telemetry callbacks and to broadcasts already gated at channel join.
  • S2 (audit trail): N/A — writes touch only chat message status/failure metadata (ai_chat_messages), not project/instance configuration resources.

@elias-ba
elias-ba force-pushed the timeout-failure-taxonomy branch from 3683332 to 5a28e60 Compare August 15, 2026 22:50
@elias-ba
elias-ba force-pushed the timeout-stuck-message-reaper branch from 01753c3 to 55042f3 Compare August 15, 2026 22:50
processing_started_at has been written on every message since it started
processing and read by nothing. This reads it.

A message is left processing forever when its job dies without emitting
telemetry. Attaching Oban's stop event covers most of that, but not the
case it cannot reach: when a job outlives the drain window, Oban stops
the producer first and kills the task after, so there is nothing left to
report it. Until something clears the row the panel stays locked for
everyone in that session, and nothing raises.

Two guards decide what to reap, because neither is sound alone. Age is
vulnerable to clock skew and to a queue that was paused. A live Oban job
for the same message is the cross-node authority. The live set is read
after the candidates, never before - a job starting in between then
appears in it and is skipped, where the other order could reap a message
whose job had only just begun.

The write is a guarded update rather than a read-modify-write, so a job
that finishes between the select and the write keeps its own result.

The grace period sits well clear of the longest a run can legitimately
take, so a slow answer is never mistaken for an abandoned one, and a
partial index keeps the every-five-minutes scan off the table.
@elias-ba
elias-ba force-pushed the timeout-failure-taxonomy branch from 5a28e60 to 1813938 Compare August 15, 2026 23:40
@elias-ba
elias-ba force-pushed the timeout-stuck-message-reaper branch from 55042f3 to 3abf115 Compare August 15, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New Issues

Development

Successfully merging this pull request may close these issues.

1 participant