Skip to content

fix: V1 schedule version bump + Migration fixes + CGS version guards - #11633

Closed
davidporter-id-au wants to merge 8 commits into
temporalio:mainfrom
davidporter-id-au:bugfix/scheduler-v13-version-ceiling
Closed

fix: V1 schedule version bump + Migration fixes + CGS version guards#11633
davidporter-id-au wants to merge 8 commits into
temporalio:mainfrom
davidporter-id-au:bugfix/scheduler-v13-version-ceiling

Conversation

@davidporter-id-au

@davidporter-id-au davidporter-id-au commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

This combines multiple fixes into a unified v1 schedule version bump. It includes:

  • A fix for Schedule v1->v2 migration
  • A fix for migration/retry during rollback, to prevent schedules re-triggering later
  • The set of PR changes / fixes made by @liam-lowe / for CGS and OSS version guards

This is being rolled into a large, bundled change, after being tested individually, because we want to minimize the number of version changes for V1 schedules.

LLM summary

This PR combines two scheduler changes that need to agree on the recorded V1 scheduler workflow version:

The combined result teaches the scheduler all v13 behavior while leaving CurrentTweakablePolicies.Version at 12. Version 13 can therefore be deployed safely before it is activated, and the ceiling can continue to hold selected namespaces at an older version.

Why migration must require version 13

The version ceiling needs to be a semantic ceiling, not just a different number in TweakablePolicies. A scheduler clamped to version 12 must behave like the historical version-12 scheduler throughout that run.

Before the merge resolution, CHASM migration configuration and signals could still influence a clamped version-12 execution. In particular, the workflow could register and consume the migration signal, persist migration-related tweakables, or execute pending migration work even though v1.29/version 12 did not understand those behaviors. That would let a supposedly compatible execution write newer decisions into history and defeat the purpose of the ceiling.

This PR therefore gates the complete migration boundary on MigrationHandoffFixes (13):

  • migration dynamic-config values are only copied into recorded tweakables at version 13 or later;
  • the migration signal channel is only registered and consumed at version 13 or later;
  • pending migration activity is only executed at version 13 or later;
  • at version 12, migration signals are intentionally ignored, matching the old scheduler rather than deferring a new behavior into an old-version run.

Version 13 is also the shared activation point for the two fixes in #11462. Keeping them behind one version avoids two workflow-version activation deploys and ensures rollback/idempotency behavior changes together with migration eligibility.

Testing and verification

  • go test -tags test_dep ./service/worker/scheduler -count=1
    • passed the full scheduler unit and replay suite after the merge;
    • covers ceiling values below, equal to, and above the current version;
    • covers version locking after the first mutable-side-effect evaluation, including version 0;
    • verifies a version-12 run neither consumes a migration signal nor invokes migration, while version 13 does;
    • covers the v13 migration reconciliation and migrated-start ID behavior from fix: [Scheduler] V1->V2 migration-eligibility fix and migrated-start ID #11462;
    • replays the checked-in historical scheduler fixtures through v1.29.
  • TEMPORAL_SDK_FLAG_7=0 GENERATE_SCHEDULER_V129_COMPATIBILITY_HISTORY=1 go test -tags integration,test_dep ./tests -run '^TestGenerateSchedulerV129CompatibilityHistory$' -count=1
    • generated a focused history using the v13-capable binary clamped to version 12;
    • enabled migration configuration, sent the migration signal, confirmed the schedule ignored it, fired a normal action, and continued as new.
  • The focused history replayed successfully with the unmodified Temporal v1.29 scheduler replayer. This reverse-case fixture/test is intentionally being kept on a separate branch rather than included in this PR.
  • make lint-code passed with no issues.

The TEMPORAL_SDK_FLAG_7=0 setting in the focused reverse check is necessary because the current Go SDK records its newer memo-encoding flag by default, while the Go SDK used by Temporal v1.29 rejects that unknown SDK flag before scheduler replay begins. The scheduler version ceiling controls scheduler workflow behavior; it does not make newer SDK-internal flags understandable to an older SDK.

Potential risks

Scheduler workflow changes carry nondeterminism risk. The main protection here is that every migration-visible decision is behind the same recorded v13 boundary, and the default remains version 12 until a separate rollout activates v13. Operators must also configure the ceiling no higher than the oldest failover/rollback peer they intend to support.

liam-lowe and others added 8 commits July 22, 2026 15:14
… ID preservation under one v13

Combines PR temporalio#11134 and PR temporalio#11427, which independently introduced a new
SchedulerWorkflowVersion = 13 for two different fixes. Shipping them
separately would require two separate version-bump deploys for the "same"
version number. This merges both behavioral changes under one shared v13:

- RefreshBeforeMigrationCheck (from temporalio#11134): the V1 scheduler's automatic
  CHASM-migration eligibility check read len(s.Info.RunningWorkflows) before
  the same run-loop iteration's processBuffer() reconciled it, so an
  actively-firing schedule never observed an idle window and deferred
  migration forever. Reconcile running-workflow status before the
  eligibility check so it sees the genuine post-completion window.

- PreserveMigratedStartIDs (from temporalio#11427): V1 discarded the workflow/request
  IDs already stored on buffered starts migrated from CHASM, breaking
  idempotency identity across the migration handoff. Prefer those IDs when
  present, falling back to the existing derivation/UUID generation.

Following temporalio#11134's two-phase-rollout rationale, this PR only teaches the
scheduler to *understand* v13 for safe replay/rollback; both fixes are
gated behind hasMinVersion(13) but CurrentTweakablePolicies.Version stays
at TriggerImmediatelyTimestamp (12). A follow-up deploy bumps Version to 13
to activate both fixes at once -- a single activation instead of two.

Brings in temporalio#11134's replay fixture (testdata/replay_migration_v1_to_v2.json.gz)
and integration test file (tests/schedule_migration_v1_to_v2_callback_compat_test.go)
verbatim, and temporalio#11427's workflow.go/workflow_test.go changes, retargeting the
version gate and forcing the version in
TestMigratedBufferedStartPreservesIdempotencyIDs since Version no longer
defaults to 13 here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
If EnableCHASMSchedulerMigration is enabled, bounces on a transient
error, and is then rolled back, the sleeping V1 scheduler workflow had
no way to notice: PendingMigration is a persisted latch that, once set,
retries the migration unconditionally on every wake-up regardless of
the current flag value. Depending on the schedule's own cadence, that
retry (and thus the migration) could fire long after the flag was
believed to be off.

Fix this in the local activity itself rather than in workflow code:
MigrateScheduleToChasm now does a live (uncached) check of
EnableCHASMSchedulerMigration right before calling
CreateFromMigrationState, and fails if it's off. The workflow's retry
loop is unchanged -- it just logs the failure and keeps going, so a
disabled migration spins harmlessly (and resumes the moment the flag
comes back on) without ever blocking the schedule's own actions.

Also arm TestScheduleMigrationV1ToV2_RolloutMigration by setting
CurrentTweakablePolicies.Version to MigrationHandoffFixes for the
duration of the test, since that fix is still dormant pending a
follow-up activation deploy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@davidporter-id-au davidporter-id-au changed the title Bugfix/scheduler v13 version ceiling fix: V1 schedule version bump + Migration fixes + CGS version guards Aug 19, 2026
@davidporter-id-au

Copy link
Copy Markdown
Contributor Author

ignore this, my thinking wasn't all that clear

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.

2 participants