Skip to content

Prevent workflow stream subscriptions from hiding cancellation - #1805

Open
1fanwang wants to merge 6 commits into
temporalio:mainfrom
1fanwang:1fannnw/workflow-stream-cancellation
Open

1fanwang wants to merge 6 commits into
temporalio:mainfrom
1fanwang:1fannnw/workflow-stream-cancellation

Conversation

@1fanwang

@1fanwang 1fanwang commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

What was changed

An activity whose workflow stream subscription is cancelled now raises
CancelledError instead of seeing the iterator end normally. Before this change,
such an activity could return success even though Temporal had requested its
cancellation.

The subscription rethrows direct task cancellation and cancellation wrapped by
WorkflowUpdateRPCTimeoutOrCancelledError. RPC timeouts and server-side RPC
cancellation keep their existing continue-as-new and terminal-workflow handling.

Why?

Activity code that loops over a subscription has no other way to learn that
Temporal cancelled it, so cleanup and cancellation reporting were skipped.

Checklist

  1. Closes: no linked issue.

  2. How was this tested:

The probe starts a local Temporal dev server, runs the regression test's
workflow and activity, waits until the heartbeating activity is polling a
workflow stream, and then cancels it. The activity catches CancelledError
directly around the subscription and returns a distinct value for each outcome.

Reproducer source: probe.py
import asyncio

from temporalio.testing import WorkflowEnvironment

from tests.contrib.workflow_streams.test_workflow_streams import (
    CancellableSubscriber,
    CancelSubscriptionWorkflow,
)
from tests.helpers import new_worker


async def main(timeout: float) -> None:
    async with await WorkflowEnvironment.start_local() as env:
        subscriber = CancellableSubscriber()
        async with new_worker(
            env.client, CancelSubscriptionWorkflow, activities=[subscriber.subscribe]
        ) as worker:
            handle = await env.client.start_workflow(
                CancelSubscriptionWorkflow.run,
                id="workflow-stream-cancel-probe",
                task_queue=worker.task_queue,
            )
            await asyncio.wait_for(subscriber.started.wait(), timeout)
            await handle.signal(CancelSubscriptionWorkflow.cancel_subscription)
            print("activity result:", await handle.result())


asyncio.run(main(timeout=10))

Before, with the stream client from main:

$ uv run python probe.py
activity result: subscription-ended

After, with this branch:

$ uv run python probe.py
activity result: subscription-cancelled
  1. Any docs updates needed?

No. The CHANGELOG entry is under Unreleased.

@1fanwang
1fanwang requested review from a team as code owners September 2, 2026 07:58
@tconley1428 tconley1428 added the ai-sdk Related to AI integrations label Sep 2, 2026

@brianstrauch brianstrauch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

1fanwang and others added 3 commits September 28, 2026 13:27
Signed-off-by: 1fanwang <1fannnw@gmail.com>
Signed-off-by: 1fanwang <1fannnw@gmail.com>
@1fanwang
1fanwang force-pushed the 1fannnw/workflow-stream-cancellation branch from 1098bf5 to b58133f Compare September 28, 2026 20:28
@brianstrauch

Copy link
Copy Markdown
Member

@1fanwang From CI:

Error: CHANGELOG.md additions must be under the Unreleased section.

@1fanwang

1fanwang commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

CHANGELOG.md additions must be under the Unreleased section.

@brianstrauch Done in 55d19f7.

@brianstrauch
brianstrauch enabled auto-merge (squash) October 1, 2026 22:03

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

ai-sdk Related to AI integrations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants