Skip to content

feat(workers): let users set the Cloud Run scale-down stabilization window - #3860

Draft
rossnelson wants to merge 2 commits into
mainfrom
gcp-scale-down-stabilization
Draft

feat(workers): let users set the Cloud Run scale-down stabilization window#3860
rossnelson wants to merge 2 commits into
mainfrom
gcp-scale-down-stabilization

Conversation

@rossnelson

@rossnelson rossnelson commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Description & motivation 💭

The GCP Cloud Run scaler holds capacity for 90 seconds after demand ends before it scales the pool down. That window is not settable from the UI, so a worker pool that runs long or bursty activities can lose capacity while work is still in flight.

This adds a Scale-down Stabilization field to the Cloud Run scaling and lifecycle section, next to the replica bounds and the utilization target. The field is a duration, matching the CLI flag.

  • The form sends the value as the rate-based scaler's no_sync_quiet_ms key. The server (WCI) already validates and applies it, so no server change is needed.
  • The edit form reads the value back from an existing version, so a round trip keeps it.
  • The field joins the same all-or-none Cloud Run group as the replica bounds and the utilization target. It defaults to 90000 ms, and 0 disables the wait.

The field uses the Holocene duration input, the same control the schedule forms use: a number plus a unit selector. The form holds a seconds duration string such as 90s, and the page converts to milliseconds when it builds the compute config. The unit selector opens on the largest whole unit, so a stored 300000 ms reads as 5 minute(s).

The CLI settled on --gcp-cloud-run-scale-down-stabilization-duration, which takes 5m or 90s. A millisecond field would have asked users to convert the value in their head, and the two surfaces would then describe one setting in two units.

This is the UI half of temporalio/cli#1167, which adds --gcp-cloud-run-scale-down-stabilization-duration.

Screenshots (if applicable) 📸

To add.

Design Considerations 🎨

One point worth a look:

The neighboring Lambda scaling inputs in this same form are raw millisecond number fields (Scale-up Cooloff (ms), Max Worker Lifetime (ms), Metrics Poll Interval (ms)). This field is a duration input instead, because that is what the CLI exposes. The form is therefore internally inconsistent until those Lambda fields get the same treatment. Converting them is out of scope here, since no CLI change asks for it.

The wire key no_sync_quiet_ms is settled: it is unchanged in the CLI PR after two rounds of review.

Testing 🧪

How was this tested 👻

  • Manual testing
  • E2E tests added
  • Unit tests added

Unit tests added or extended:

  • shared.test.ts: the 90s default applies on both the edit and the create schema; 0s and a whole-millisecond 0.1s are accepted; a negative value, a sub-millisecond value, and a unitless value are all rejected. The sub-millisecond case matches the CLI, which rejects that input rather than rounding it.
  • shared.test.ts: the duration-to-milliseconds converters round-trip in both directions, including the 90s value the CLI defaults to.
  • deployments-service.test.ts: no_sync_quiet_ms is present with the default; a custom value round-trips through encode and decode; 0 is sent as 0 rather than falling back to the default.

Full suite run on this branch: 3030 passed, 2 skipped, 0 failed. pnpm lint and pnpm check both report 0 errors.

Steps for others to test: 🚶🏽‍♂️🚶🏽‍♀️

  1. Go to a worker deployment and start Create Version, or create a serverless worker.
  2. Select Google Cloud Run as the compute provider.
  3. Open Scaling and lifecycle with Show defaults. The new Scale-down Stabilization field shows below Utilization Target, prefilled with 90 second(s).
  4. Set 5 minute(s) and save. The created version's compute config carries no_sync_quiet_ms: 300000 on the scaler.
  5. Open Edit on that version. The field shows 5 minute(s), not the default.

Checklists

Draft Checklist

  • Add a screenshot of the Cloud Run scaling section
  • Manual test against a real Cloud Run worker pool

Merge Checklist

Issue(s) closed

FE-192. Companion to temporalio/cli#1167 (COM-241).

Docs

Any docs updates needed?

No UI docs change. The setting is documented with the CLI flag in temporalio/cli#1167.

…indow

The GCP Cloud Run scaler holds capacity for 90 seconds after demand ends
before it scales the pool down. That window is not settable from the UI,
so a pool that runs long or bursty activities can lose capacity while work
is still in flight.

Add a Scale-down Stabilization field to the Cloud Run scaling and lifecycle
section. The form sends the value as the rate-based scaler's no_sync_quiet_ms
key, and the edit form reads it back from an existing version. The field is
part of the same all-or-none Cloud Run group as the replica bounds and the
utilization target, and it defaults to 90000 ms. A value of 0 disables the
wait.

The units are milliseconds, which agrees with the other scaling inputs in
this form. The CLI accepts a duration string for the same setting and
converts it to milliseconds before it sends the request.

Refs: temporalio/cli#1167
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview Aug 25, 2026 2:14pm

Request Review

The CLI settled on a duration flag, --gcp-cloud-run-scale-down-stabilization-duration,
which takes 5m or 90s. A millisecond field in the UI asks users to convert
the value in their head, and the two surfaces then describe one setting in
two units.

Use the Holocene duration input for the field, the same control the schedule
forms use. The form holds a seconds duration string such as 90s, and the page
converts to milliseconds when it builds the compute config, so the wire key
no_sync_quiet_ms is unchanged. The edit form converts back, and the unit
selector opens on the largest whole unit, so a stored 300000 ms reads as
5 minutes.

The field accepts a whole number of milliseconds, which agrees with the CLI.
A sub-millisecond value is rejected rather than rounded.

Refs: temporalio/cli#1167
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