Repository navigation
Conversation
A subscription ended only with the run, so a workflow that stopped reading kept being woken. The command removes the record and its pending notification, writes its event naming the subscribe event, and the completion drops the run from the channel's listeners the way the registration added it. A reset run re-applies both events in order.
This was referenced Oct 2, 2026
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds the command that ends a workflow's subscription to a notification channel.
What changed?
UnsubscribeNotificationChannelremoves the run's subscription record and the notification waiting on it, and writesWorkflowNotificationChannelUnsubscribedwith the channel and the id of the subscribe event it ends. A notification a scheduled event already carries stays in History.UnregisterWorkflowListeneron the channel service forgets the run on the channel's shard. Deregistrations run before registrations and skip a channel the run subscribes to again by the end of the task, so unsubscribe-then-subscribe in one task keeps the listener and subscribe-then-unsubscribe leaves none. A registration for a channel the run left in the same task is skipped too.BAD_UNSUBSCRIBE_NOTIFICATION_CHANNEL_ATTRIBUTESfor missing attributes or an empty or over-long name only. The command is listed with the non-closing commands in the attribute validator.DescribeWorkflowExecutiondrops the entry with the record.tests/unsubscribe_channel_test.gocovers the lifecycle, the no-subscription cases, same-task pairs, validation and reset. Unit tests cover the removal on the Workflow component.Part of AI-198 (epic AI-37).
Why?
Until now a subscription ended only with the run, so a workflow that stopped reading a stream kept being woken by its channel for the rest of its life, and a long-lived workflow could not rotate channels under the per-workflow limit. The external stream reader can now unsubscribe when its reader closes or reaches the end.
How did you test it?
go build ./..., golangci-lint and theerrortypevet are clean on the touched packages. Unit tests ran for./chasm/lib/workflow/...,./chasm/lib/channel/...,./service/history/api/...and the completion handler. The functional tests ran with-tags disable_grpc_modules,test_dep: an unsubscribe records its event naming the subscribe event, the channel and describe drop the run, a notify afterwards wakes nothing while the channel retains it, and subscribing again records a new event and is handed the latest. An unknown channel and a linked name record events with no subscribe event and change nothing, subscribe and unsubscribe in one task leave no listener and never reach the channel, the reverse keeps the listener under the new event. An empty name fails the task with the new cause and the retry completes clean. A reset run keeps only the subscription the source still had, the dropped channel forgets the reset-away run on its next notify, and the kept channel reaches the reset run. The notification channel, linked channel, inline handoff, stream channel and describe suites pass.