Skip to content

Prevent stale status/fix-jobs responses from overwriting fresher data #596

@cpcloud

Description

@cpcloud

Summary

handleStatusMsg unconditionally overwrites m.status with whatever arrives. When multiple refresh batches overlap (e.g. a poll tick fires while an SSE-triggered refresh is still in flight), an older fetchStatus() response can land after a newer one and overwrite fresher data.

The same applies to fetchFixJobs() responses.

Current behavior

handleTickMsg, handleSSEEventMsg, and consumeSSEPendingRefresh all fire fetchJobs() + fetchStatus() (+ sometimes fetchFixJobs()) in a single tea.Batch. Only fetchJobs is gated by loadingJobs — status and fix-jobs have no overlap protection.

jobsMsg already has a seq field that gates stale responses. statusMsg and fixJobsMsg do not.

Possible approaches

  1. Sequence token — add a monotonic seq to statusMsg/fixJobsMsg (matching the jobsMsg pattern), discard responses where msg.seq < m.statusSeq
  2. In-flight guard — add loadingStatus/loadingFixJobs booleans, skip fetches when already in flight (like loadingJobs does for jobs)
  3. Request cancellation — cancel the previous fetch's context when a new refresh starts, so the old response never arrives
  4. Server-side timestamp — only apply a response if its timestamp is newer than the last applied one

Context

Discovered during #593 (SSE subscription for TUI). The pattern is pre-existing and affects both polling and SSE equally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions