Skip to content

[Bridge] Moved the stream runtime to sdk-streams. - #272

Closed
moetemp wants to merge 88 commits into
moe/bridge/v2/dr39-follow-lanefrom
moe/bridge/v2/dr40-sdk-streams
Closed

moetemp wants to merge 88 commits into
moe/bridge/v2/dr39-follow-lanefrom
moe/bridge/v2/dr40-sdk-streams

Conversation

@moetemp

@moetemp moetemp commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

What changed?

This PR moves Bridge's stream runtime to sdk-streams. It merges Jetty's jp28, pins Core to kb1 84dc65fd and takes the temporalio-streams crate at sb3 472e700f.

  • Nexus progress comes in the Workflow Task attachments as Any(NexusOperationProgress), keyed by endpoint, service, operation and token. The fold and the deliveries pass the crate's nexus_progress_folds.json.
  • The Nexus progress and sync call messages come from the crate's api_nexus copy. The system Nexus services come from the crate's WIT, which no longer exports the four notifier ops, so temporalio.workflow drops them.
  • StreamReader records each batch in History by default. replay_from_store=True is the opt-in for direct reads. A direct read cuts its Workflow Task like a follow step, and its recheck caps at 5 minutes.
  • The direct-read caches share the byte-bounded BatchCache. The Nexus follower's batch is FollowerBatch.
  • notify_on_append is on by default, so Bridge progress needs no setup.
  • The Log, the driver, the archive and PostgreSQL left with jp28's move-out. They're on the optional layers [FROZEN][Bridge][Optional] Restored the notification log, the stream driver and the archive. #273 and [FROZEN][Bridge][Optional] Restored the PostgreSQL store. #274. The Bridge demos left too, and the live tests keep their helpers.
  • Both Nexus generators pin nexgen 3c60ecc9.

Why?

sdk-rust holds nothing stream-specific now, so the Bridge pieces of the stream runtime and its API live in sdk-streams. Recorded batches work on every server, Temporal Cloud included.

How did you test it?

Link to a test plan if any -

  • Unit Tests
  • Staging
  • End to End Tests

Core k1 holds no stream code. The bridge links temporalio-streams from moetemp/sdk-streams, patched onto the submodule's sdk-rust crates so both see one Connection type, and the stream protos come from the crate checkout.
ss3 adds the Workflow publish, eviction and shutdown calls and the OutputRecord message that left Core's workflow commands.
The Worker runs the payload codec on the records and calls PublishWorkflowTask before it completes the activation, and a failed call fails the Workflow Task. Each eviction calls RunEvicted and Worker shutdown calls ShutdownWorker, keyed by a fresh worker id per Worker.
The patch hides the crate's own sdk-rust rev from the build. The FIPS tree check now counts only normal and build edges.
Each Worker keys its run state by its own worker id, so the stream keeps every record in order across the restarts and the chain still closes.
The store, the reader rules and the chain close now run in the temporalio-streams crate, and the Worker publishes the records.
ss3 now closes an ended run's chain at Worker shutdown too, and ss4 adds the Core mock Worker tests.
… it.

ss3 now proves the chain close from the run's History, and ss2 adds the crate's fips feature.
Moved the Core pin to 969a0883 and the sdk-streams dependency to sj1 e86e63a5, and regenerated the protos.
Core now hands the server's attachments in job 17. The Worker decodes each wake's close outcome with the reader's codec, and the instance folds the wakes with the shared rule.
sj2 holds the notifier and owner clients that Core served before.
…s in the publish call.

The Worker knows an owner Activity by the header it set. It sends each live resolution as the server gave it, before the decode pass, so readers decode the failure with their own codec.
It restores the one-line ACL command in the crate's Redis docs.
kj5 vendors no stream API, so the stream messages, enums and notifier messages now generate from the crate's api_stream copy. The workflow service client lost the notifier RPCs.
The workflow service client has no notifier RPCs on kj5, since the stream runtime holds the notifier client.
The Core pin is kb1 and the sdk-streams dependency is sb1. The generated files come from them.
The stream service's Nexus path note in _body.py came back. The tests read the contract and the token vectors from the crate's nexus directory.
…rom the crate.

The Nexus progress and sync call messages come from the crate's api_nexus copy. The system Nexus generator reads the workflow and notification service WIT from the crate.
The instance folds a task's progress to one per endpoint, service, operation and token, and gives it to each started operation with that key. The fold and the deliveries pass the crate's vectors.
Core's client has no stub for it, so ClientTransport calls the crate's call by method path on the client's connection.
The server caps the recheck at 5 minutes, not an hour.
The core Worker reads it, so it shouldn't import contrib.streams to get it.
The Core entries described a stream runtime that left Core. The Worker now publishes through PublishWorkflowTask, and temporalio-streams runs the store.
The owner's codec encoded it, so a codec that keys on the context failed the reader's task. No reader reads a wake's close result, so it stays as sent.
Demos don't ship in an SDK. The push test wakes through producer notifications, since the driver moved to the optional stack.
Only a read or a replay moves the hold, so a long run must Continue-as-New in time.
# Conflicts:
#	temporalio/bridge/Cargo.lock
#	temporalio/bridge/Cargo.toml
#	temporalio/bridge/proto/streams/streams_pb2.py
#	temporalio/bridge/sdk-core
#	temporalio/contrib/streams/README.md
#	temporalio/contrib/streams/__init__.py
#	temporalio/contrib/streams/_body.py
#	temporalio/contrib/streams/_capabilities.py
#	temporalio/contrib/streams/_cursor.py
#	temporalio/contrib/streams/_handles.py
#	temporalio/contrib/streams/_plugin.py
#	temporalio/contrib/streams/_supersession.py
#	temporalio/contrib/streams/_wire.py
#	temporalio/contrib/streams/_workflow.py
#	temporalio/contrib/streams/docs/migration.md
#	temporalio/contrib/streams/docs/store-capabilities.md
#	temporalio/contrib/streams/memory.py
#	temporalio/contrib/streams/redis.py
#	tests/contrib/streams/test_unsupported_owners.py
The new crate makes each append wait for its stream notification and drops the optional stack.
The crate's WIT no longer exports the four System Nexus notifier ops, so temporalio.workflow and the outbound interceptor lose them. The stream contract regenerates with nexgen 3c60ecc9.
With notifications on by default, the notifier wait found no owner and ended the read inside its owner start grace.
The Workflow reader ships in this stage, the Nexus notes belong to a later one, and the harness table and lane notes aren't user docs.
No released marker lacks the run that read it.
The entries described a stream runtime in Core and an attempt shift that changed since.
The crate script defaults to the shared cluster on 7101. The server ref pointed at an old commit.
# Conflicts:
#	scripts/streams_live_lane.sh
@moetemp

moetemp commented Oct 18, 2026

Copy link
Copy Markdown
Owner Author

Closing this in favor of the re-cut Bridge stack (#296 to #320). Its content is now in #296, #297.

@moetemp moetemp closed this Oct 18, 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