Repository navigation
Conversation
`make fmt` left these two files dirty, which fails the `fmt` job. The proto also carried a truncated comment for a field that is no longer there.
The stream log methods on `ExecutionStore` had no fault-injection or telemetry wrapper, so `make go-generate` left the tree dirty.
Both were rewritten to point at `add_stream_log`, which dropped `nexus_incoming_services` from the Cassandra upgrade path and `tasks_v2` from the SQLite one. A released version has to stay what it was.
Cassandra goes to 1.14, SQLite to 0.12, MySQL and PostgreSQL to 1.20. The MySQL and PostgreSQL stores already query `stream_log`, so their base schema needed the table too.
It holds one cluster per arm for the whole run, which outlasts the dedicated pool and parks the functional suite until the 35 minute timeout.
Three placeholders carried a trailing digit. MySQL connections interpolate parameters, so the digit was appended to each value and a read returned batches past the offset it asked for.
The orphan comment dropped from the `.proto` still rode the generated field, which leaves `make proto` dirty.
The `api-go` branch was rebased onto its upstream `main`, which pulls in newer gRPC and OpenTelemetry requirements through the module graph.
The new api pin ships the nexusoperation proto, so the generated import map has to list it.
The module pins its own grpc version and has to track the root module after the api pin bumped it.
The mixed brain tests live in their own module, so the root go test invocation cannot reach them.
The metric SDK returns a nil slice when no exemplar was recorded and an empty one when the reservoir was already allocated, which made the comparison flaky.
The log is appended to, so a failure from an earlier run kept failing every later verification.
Taken from upstream temporalio/temporal temporalio#11906. The api version this branch pins rejects a system payload that is not binary/protobuf, so the endpoint has to refuse one instead of labelling it.
Payloads live in the CHASM component, so the table, the store methods, the four schema bumps and the scavenger marker had no caller on the serving path. The internal protos reserve the field numbers the log addressing used.
The completion path reached the stream with the request context's engine, which only serves shards this host owns. Registration now resolves its start offset in one transition, and routed calls made under the workflow lock carry a bounded deadline.
Cold replay walks every page of history for the recorded ranges instead of stopping at the first. A range that is truncated, deleted or over the replay budget fails the task with its own cause rather than handing matching a retry. Slices now name the run that holds the stream.
A refused publish or subscribe came back as a plain error, which failed the completion call and left the worker retrying the same command with nothing in History saying why.
The publish commits with the task, so a task that fails after publishing has to leave no event, no offset and no message behind.
Delivery to a workflow drops anything that is not data, so a producer leaving the field unset got an offset for a message no subscriber ever saw.
The batch and the frontier commit in one transition and the execution serializes transitions, so the pin only made an outside producer fail when the workflow published in between. The stripe lock and the separate create step went with it.
The event bounds its batch with a from and a to offset like every other range in this API.
…-reset-failover # Conflicts: # chasm/lib/workflow/stream_admission_test.go # chasm/lib/workflow/stream_cursor_test.go
A reset re-ran the reset-point task, but the range that task had been given from a stream the base run owned lived only in the base run, so the reset run's first task saw an empty stream where the base run had seen input. The reset now reads the range off the completion event it does not copy and seeds the reset run's own stream with those records at their offsets; ranges recorded before the reset point are still re-supplied from the base run.
…-reset-failover # Conflicts: # chasm/lib/stream/doc.go
A batch copied into a reset run's stream is as old as it was in the base run, so the copy carries the source's stamp and the bytes count toward what the new stream holds, the same as an append would.
This was referenced Oct 1, 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 carries stream subscriptions through a workflow reset and characterizes namespace failover.
What changed?
service/history/workflow/mutable_state_rebuilder.gorecreates a cursor from the subscribe event and moves it with each completed task's range. A range for a stream with no cursor proves a service subscription, which leaves no event, so the cursor comes from the range.InheritStreamsOnResetinchasm/lib/workflow/workflow.gocopies what only the base run knows. A cursor on another execution's stream keeps reading it from the base run's last frontier. A cursor on an owned stream gets the reset run's own stream, starting where the cursor stands. The offset space continues, so a range in this run's History names one run. A publisher's reset run still restarts its stream at offset zero, andTestResetOfAPublisherRestartsItsStreamAtZeropins that open gap.service/history/ndc/workflow_resetter.gore-delivers the input the reset-point task consumed. It reads that task's ranges off the completion event it doesn't copy, andStream.Seedputs those records into the reset run's stream at their offsets. A seeded batch keeps the source's age and counts as held bytes, so the byte cap and retention see the copy as the original. Records the base run took after that task stay on the abandoned timeline, and nothing records it.tests/xdc/stream_failover_test.gopins failover in both replication modes. State-based replication carries the stream, its batches and the cursor, and the workflow goes on there. Event-based replication rebuilds only the cursor, so its first task fails withSTREAM_RANGE_UNAVAILABLE.Part of AI-198 (epic AI-37).
Why?
Reset is where the two halves of a subscription, the events and the CHASM state, have to agree. A reset run is rebuilt from events, and the cursors are CHASM state the events never touch. On failover, state-based replication carries a stream and event-based replication doesn't yet. Both read better after the behavior they characterize.
How did you test it?
go build ./...andmake fmtare clean. Unit tests ran for./chasm/lib/stream/,./chasm/lib/workflow/and./service/history/..., with the seed tests. The functional reset tests intests/stream_reset_test.goand the XDC failover suites ran with-tags test_depon this tip.