fix(actions): never drop a child update from WatchForUpdates by earlybard · Pull Request #8166 · flyteorg/flyte · GitHub
Skip to content

fix(actions): never drop a child update from WatchForUpdates - #8166

Draft
earlybard wants to merge 1 commit into
flyteorg:mainfrom
earlybard:fix/actions-watch-never-drop
Draft

earlybard wants to merge 1 commit into
flyteorg:mainfrom
earlybard:fix/actions-watch-never-drop

Conversation

@earlybard

Copy link
Copy Markdown
Contributor

Tracking issue

Closes #8104

Why are the changes needed?

ActionsClient.notifySubscribers drops an update when a parent's subscriber channel is full (subscriber channel full, dropping update for parent action). If that update is a child's terminal phase, the parent's SDK informer never learns the child finished. It doesn't re-list, so the parent waits forever and the run has to be aborted. Reconnecting wouldn't help either: the snapshot comes from TaskAction CRs, and finished children's CRs are usually gone by then.

Raising actions.watchBufferSize only moves the threshold. We run it at 1000 and still had a parent hang with all 546 of its children SUCCEEDED, under backend load (etcd throttling) that slowed the stream.

What changes were proposed in this pull request?

  • Each subscription parks undelivered updates in a map keyed by child action name, and a per-subscription pump goroutine feeds them into the channel the caller already reads.
  • A newer update for a child that's still parked replaces the older one. The informer only needs each child's latest state, so memory is bounded by the number of children rather than by how fast the stream drains, and nothing is dropped.
  • notifySubscribers never blocks, so a slow stream can't stall the watch workers.
  • Subscribe/Unsubscribe keep their signatures, so ActionsService and the mocks are unchanged. Unsubscribe stops the pump, and the pump closes the channel, so a send can't race the close.
  • watchBufferSize still sizes the subscriber channel ahead of the parked map, and still sizes the worker channels as before.

How was this patch tested?

  • New tests in actions/k8s/client_subscribe_test.go: 1000 children through a 10-slot subscriber all arrive; a parked update is replaced by a newer one for the same child while other children keep their order; Unsubscribe closes the channel. The run-scoping test now waits for async delivery.
  • go test -race ./actions/..., plus -count=50 on the subscribe tests.
  • go vet ./actions/..., gofmt -l actions/ and go build ./... are clean.

Labels

  • fixed

Check all the applicable boxes

  • I updated the documentation accordingly.
  • All new and existing tests passed.
  • All commits are signed-off.

🤖 Generated with Claude Code

notifySubscribers dropped an update whenever a parent's subscriber
channel was full. A dropped terminal update means the parent's SDK
informer never learns the child finished, and since it never re-lists,
the parent waits forever. Raising watchBufferSize only moves the
threshold: a 546-child parent still hung at 1000.

Each subscription now parks undelivered updates in a map keyed by child
action name, with a pump goroutine feeding the caller's channel. A newer
update for a still-parked child replaces the older one, so memory is
bounded by the number of children and nothing is dropped. The channel
returned by Subscribe is unchanged, so the service and mocks are too.

Closes flyteorg#8104

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Dylan Jenkins <dylan.jenkins@ga.gov.au>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[flyte2] Parent action hangs forever when the WatchForUpdates subscriber channel drops a child's terminal update

1 participant