8000 feat(resumption): throttle paused-task replay when tasks queue is busy by andrzejfudro · Pull Request #986 · google/xmc · GitHub
[go: up one dir, main page]

Skip to content

feat(resumption): throttle paused-task replay when tasks queue is busy - #986

Merged
andrzejfudro merged 6 commits into
mainfrom
feat/ess-replay-backlog-throttling
Sep 29, 2026
Merged

andrzejfudro merged 6 commits into
mainfrom
feat/ess-replay-backlog-throttling

Conversation

@andrzejfudro
@andrzejfudro andrzejfudro commented Sep 25, 2026 •
Copy link
Copy Markdown
Collaborator

Summary

The ESS resumption worker now pauses replay while xmc-tasks-stream is busy, so replaying paused tasks can't push Redis toward its memory limit.

Key Changes

  • task_queue: new Client.CalculateBacklog computes pending + lag using XINFO GROUPS and XRANGE. XRANGE is skipped when pending alone reaches the threshold, and otherwise reads only threshold - pending + 1 entries, so the result is capped just above the threshold. A missing stream counts as zero backlog. Cases that silently fall back to an empty backlog (missing or unsupported Redis client, missing consumer group) log a warning. A compile-time check makes sure the production publisher supports the needed Redis commands.
  • resumption worker: before each batch it checks the backlog against max_backlog_threshold from the trigger message (default 500). If the backlog is at or above it, the worker waits 10s (cancellable) and goes back to the top of the loop, so pause state and fencing are re-checked before anything is replayed. The worker takes a single TaskQueue dependency (enqueue + backlog), which task_queue.Client satisfies.
  • Tests: backlog calculation edge cases, plus throttling (including backlog == threshold and the default threshold), error, cancellation, re-pause and fencing paths in the worker.

Out of scope

  • Lease extension: the design doc also calls for extending the message lease while throttled and after each batch.
  • Metrics (xmc_resumption_throttles_total etc.) come in a separate PR.

Verification

  • bazel test //internal/task_queue:task_queue_test //cmd/experiment_state_server/resumption:resumption_test (Passed)
  • bazel build //cmd/experiment_state_server/... (Passed)

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823

Before fetching each batch, the ESS resumption worker checks the backlog
on xmc-tasks-stream (pending + lag via XINFO GROUPS and a capped XRANGE).
If it reaches max_backlog_threshold, the worker waits 10s and returns to
the top of the loop, so pause state and fencing are re-checked first.

Backlog calculation lives in the task_queue client so ESS only depends on
a small BacklogChecker interface. ExtendClaim is left as a TODO until the
lease-extension API lands.

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823
@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces downstream task queue backlog checking and throttling to the ResumptionWorker. It adds a BacklogChecker interface and implements Redis stream backlog calculation (pending + lag) via CalculateStreamBacklog to pause task replay when the backlog exceeds a specified threshold. Comprehensive unit tests and Bazel build updates are also included. The review feedback suggests two key improvements: replacing time.After with time.NewTimer in the throttling loop to prevent potential short-term memory leaks, and optimizing the backlog calculation to skip or limit XRANGE queries when the pending message count already meets or exceeds the threshold.

Comment thread internal/task_queue/backlog.go Resolved
- Use time.NewTimer with explicit Stop for the throttle wait and extract
  it into a reusable waitOrCancel method.
- Skip XRANGE when pending alone meets the threshold and otherwise read
  only threshold - pending + 1 entries.

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823
…ty backlog fallbacks

- Merge PayloadPublisher and BacklogChecker into a single TaskQueue
  interface so the task queue client is passed once.
- Warn when backlog inspection silently falls back to an empty backlog
  (missing/unsupported Redis client, missing consumer group).
- Add tests for backlog == threshold and the default threshold fallback.

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823
- Merge throttle decision cases into a single table test.
- Share worker setup across stop-while-throttled tests.
- Drop waitOrCancel tests already covered by the throttling tests.

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823
@andrzejfudro
andrzejfudro marked this pull request as ready for review September 28, 2026 12:25
@github-actions
github-actions Bot requested a review from janzak-dev September 28, 2026 12:25
Comment thread internal/task_queue/backlog.go Resolved
Move the stream backlog logic into redisclient as PublisherClient.BacklogLength,
using the publisher's stream and a caller-provided consumer group.
task_queue.Client.CalculateBacklogLength now takes the group and delegates.

Address review feedback:
- Rename CalculateBacklog to CalculateBacklogLength and document the capped count.
- Return 0 when the stream disappears before XRANGE (pending entries go with it).
- Log pause_duration when throttling replay.

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823
…sher

TAG=agy
CONV=089ef675-f585-4067-9e62-27ef0bad0823
@andrzejfudro
Copy link
Copy Markdown
Collaborator Author

@janzak-dev While addressing the comments I noticed that the backlog.go was put in the wrong place (in the taskqueue instead of redisclient). That's why more things were changed since your last review, all of it is intentional.

@andrzejfudro
andrzejfudro added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit b3f1fca Sep 29, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0