Skip to content

feat(dynamic-labels): add a capacity-type label to choose spot or on-demand per job - #5485

Open
atsikham wants to merge 2 commits into
github-aws-runners:mainfrom
atsikham:feat/dynamic-labels-capacity-type
Open

atsikham wants to merge 2 commits into
github-aws-runners:mainfrom
atsikham:feat/dynamic-labels-capacity-type

Conversation

@atsikham

Copy link
Copy Markdown
Contributor

Fixes #5484

Summary

The capacity type (spot or on-demand) of a runner configuration is fixed by instance_target_capacity_type, and a workflow job cannot choose it. This PR adds the dynamic label ghr-ec2-capacity-type:spot|on-demand, so one runner configuration can serve both kinds of jobs instead of needing a separate configuration for each.

Changes

  • New label ghr-ec2-capacity-type:<spot|on-demand>. The value overrides INSTANCE_TARGET_CAPACITY_TYPE for the runner created for that job. The value is not case-sensitive.
  • Any other value raises InvalidRunnerLabelsError, the existing error for labels that are permanently invalid and must not be retried.
  • The effective capacity type is resolved once before the runner is created, in runner-creation.ts. The label is removed from the fleet overrides, so it is not sent to AWS. Because the resolved type is used for the request, the on-demand failover follows it: it applies to jobs that use spot and never to jobs that use on-demand.
  • With use_dedicated_host = true the label is ignored, because RunInstances does not support spot. A spot value writes a warning to the log.
  • For a job with on-demand, the value of ghr-ec2-max-price is not passed to the fleet request, because it only applies to spot.
  • docs/configuration.md: new row in the basic fleet overrides table and a "Capacity type" section that describes the behavior above, the limitation for spot request tags (they come from the launch template), and a policy example that allows only spot.

Test plan

  • scale-up.test.ts: parsing (both values, not case-sensitive), validation (accepted and rejected values), and runner creation: on-demand label in a spot configuration, spot label in an on-demand configuration, no label, max price with spot and with on-demand, dedicated host, and an unsupported value. The tests for the resolution fail without the change in runner-creation.ts.
  • dynamic-labels-policy.test.ts: restricted_keys on capacity-type allows spot and rejects on-demand.
  • Full test suites of libs/compute-providers (369 tests) and functions/control-plane (352 tests)
  • eslint, prettier and tsc --noEmit

…demand per job

The label ghr-ec2-capacity-type:spot|on-demand overrides the capacity type of
the runner configuration for one job. Other values are rejected as invalid
runner labels. The label is ignored for dedicated hosts, and the max price is
not passed to the fleet request for on-demand runners.
@atsikham
atsikham requested a review from a team as a code owner September 25, 2026 22:01
resolveCapacityType is now one entry in a list of resolvers applied in order
before runner creation, so a future per-job override can be added as another
resolver without changing createRunners.

This branch has not been deployed

No deployments
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.

feat(dynamic-labels): add a capacity-type label to choose spot or on-demand per job

2 participants