Skip to content

Addressed linked channels by Execution, on workflows and activities. - #17

Closed
moetemp wants to merge 4 commits into
moe/AI-198-srv-13-listener-callbacksfrom
moe/AI-198-srv-14-execution-reference
Closed

moetemp wants to merge 4 commits into
moe/AI-198-srv-13-listener-callbacksfrom
moe/AI-198-srv-14-execution-reference

Conversation

@moetemp

@moetemp moetemp commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

This PR addresses a linked channel's owner as an Execution, a workflow run or a standalone activity, and gives a standalone activity linked channels of its own.

What changed?

  • The five channel calls read execution in place of workflow_execution, and linked_to on a notification and on DescribeChannelResponse is an Execution with its type, business id and run id. The frontend settles the type before routing: WORKFLOW and ACTIVITY as given, unset as WORKFLOW, NEXUS_OPERATION refused with InvalidArgument. The HTTP routes bind the business id alone and cannot set the enum, so the gateway annotates each call with the kind of route it matched and the frontend reads activities/ as ACTIVITY. channel.linkedKindEnabled off still ignores execution and reaches the independent channel.
  • The internal channel protos carry the Execution too, on the numbers the public messages use, and the linked RPCs route on execution.business_id. The channel service's five linked handlers are written once over a channel.LinkedOwner and dispatched on the execution's type to the Workflow or the Activity component. channel.LinkedChannels holds the create path and the bound for both owners, and channel.maxLinkedChannelsPerWorkflow keeps its name and applies per execution.
  • The standalone Activity holds LinkedChannels as the Workflow does, with the retained ring, callbacks and pollers. The activity is not among its channels' listeners: a workflow run is woken through its next Workflow Task, and an activity has no event like it to carry a notification, so a notify reaches callbacks and pollers only, the listener count leaves it out and DescribeChannel lists no owner entry. The owner's archetype decides this, through channel.OwnerListens.
  • A stream a standalone activity owns notifies stream/<name> linked to the activity, in place of the independent stream/<activity id>/<name>. A workflow activity's stream keeps stream/<activity id>/<name> linked to the workflow, and a standalone stream keeps the independent stream/<stream id>. stream.OwnedChannelAddress(owner, name) is the one derivation of channel name and linked execution for a stream owner, so the CLI and the SDKs compute what the server does. The activity's completion closes its streams and announces the close, as a workflow does for its activities' streams.
  • Linked channels are detached from their owner's lifecycle. CHASM drops a child's tasks once an ancestor is closed, so the callback post handed over in the transaction that completes the activity was never sent. Detached, the post goes out. The service still refuses every call on a closed owner.
  • tests/activity_channel_test.go covers notify, poll and describe on an activity with and without the run id, the probe on an untouched name, a URL callback posted with linkedTo of type ACTIVITY, the stream announcing its appends and its close, the HTTP activity route inferring the type, the switch off ignoring execution, and NEXUS_OPERATION refused. The workflow cases assert the type on linked_to. Unit tests cover the frontend resolution, the channel address derivation and the activity owner rule.

Part of AI-198 (epic AI-37).

Why?

The proposal's review asked for a linked channel to be addressed by a general execution reference rather than a workflow, so a stream a standalone activity owns can have a linked channel like a workflow's stream has. The API already had temporal.api.common.v1.Execution, so the public change is a field swap and the server change is the owner abstraction behind it. The activity owner differs from the workflow owner in one way, it cannot be woken, and that difference is stated where it is decided rather than spread over the handlers.

How did you test it?

  • Unit Tests
  • Staging
  • End to End Tests

go build ./..., golangci-lint and the errortype vet are clean on the channel, activity, workflow and stream libraries, the frontend and tests. Unit tests ran for those packages, with the new cases for the resolution of Execution, the channel address of a stream owner and the activity owner rule. The functional tests ran with -tags disable_grpc_modules,test_dep: the new activity channel suite, and the notification channel, linked channel, inline handoff, stream channel, describe channels and unsubscribe suites, with the workflow cases unchanged apart from the type assertions on linked_to and the owner helper's type. The api-go pin to the Execution head was cascaded through every lower layer first, with the owner read as an Execution on the layers that reach it.

The five channel calls and linked_to name the owner as an Execution. The
frontend settles the type, from the HTTP route where the path bound only
the business id. A standalone activity holds linked channels as a workflow
run does, but is not among their listeners: nothing like a Workflow Task
would carry a notification to it.
The stream notifies stream/<name> linked to the activity in place of the
independent stream/<activity id>/<name>, and the activity's completion
closes its streams, which is the last change. Linked channels are detached
from the owner's lifecycle so that close reaches a callback after the owner
ended.
The execution and linked_to fields take the numbers the public messages
use, and nothing stays reserved, since the earlier shape never shipped.
@moetemp

moetemp commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

Replaced by #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29, #30, #31, #32, #33, #34, #35, #36 and #37.

Same content, split into 20 PRs in the v3 series: the notification channel first, then the streaming interface, then native streams and the rest. The branch stays as a pin.

@moetemp moetemp closed this Oct 3, 2026
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.

1 participant