Skip to content

feat: spot instance support with on-demand fallback#54

Merged
kurok merged 1 commit into
mainfrom
feat/spot-support
Jul 2, 2026
Merged

feat: spot instance support with on-demand fallback#54
kurok merged 1 commit into
mainfrom
feat/spot-support

Conversation

@kurok

@kurok kurok commented Jul 2, 2026

Copy link
Copy Markdown

Closes #39 — roadmap (#49) Phase 2. The single largest cost lever; pairs with capacity fallback (#40).

Why

CI runners are the textbook spot workload — short-lived, ephemeral (--ephemeral), restartable — and spot is typically 60–90% below on-demand.

New inputs (start mode)

market-type: spot            # on-demand (default) | spot
spot-fallback: on-demand     # on-demand (default) | fail
spot-max-price: ''           # optional; empty = on-demand price cap

Behavior

  • Spot request: InstanceMarketOptions with SpotInstanceType: one-time + InstanceInterruptionBehavior: terminate — no persistent request to leak; stop terminates identically to on-demand.
  • Zero param diff for on-demand: no InstanceMarketOptions emitted (regression-tested).
  • Composes with Capacity resilience: ordered fallback across subnets/AZs and instance types #40: launchAcrossMarkets runs the whole instance-type × subnet chain on spot first, then (unless spot-fallback: fail) the whole chain again on-demand.
  • Fallback triggers only on capacity/price codes (InsufficientInstanceCapacity, SpotMaxPriceTooLow, …); a fatal error aborts without downgrading.
  • Output market-type-used reports the realized market.
  • spot-max-price validated as a positive decimal at config parse.

Tests / build

  • tests/spot.test.js: buildMarketOptions (one-time/terminate/MaxPrice), buildMarketPlan, launchAcrossMarkets (spot success without on-demand attempt, capacity fallback exactly once, SpotMaxPriceTooLow fallback, spot-fallback: fail propagation, fatal-abort-no-fallback) + config validation. 159 tests pass (was 142). Lint clean, dist rebuilt (verify-dist green).

Docs

  • README "Saving costs with spot" with the interruption trade-off + recommended pattern; inputs/outputs tables; action.yml descriptions.

Interruption honesty

A spot runner can be reclaimed mid-job (2-min warning); ephemeral registration means it auto-deregisters and the job re-runs cleanly rather than hanging — documented.

CI runners are the textbook spot workload — short-lived, ephemeral, restartable
— and spot is typically 60-90% cheaper. New start-mode inputs:

  market-type:    on-demand (default) | spot
  spot-fallback:  on-demand (default) | fail
  spot-max-price: '' (optional; empty = on-demand price cap)

- Spot launches request InstanceMarketOptions with SpotInstanceType=one-time and
  InstanceInterruptionBehavior=terminate — no persistent spot request to leak;
  stop mode terminates identically to on-demand. On-demand launches are
  byte-identical to before (no InstanceMarketOptions).
- Composes with the capacity fallback (#40): launchAcrossMarkets runs the whole
  instance-type × subnet chain on spot first, then (unless spot-fallback: fail)
  the whole chain again on-demand. Fallback triggers only on capacity/price
  codes (InsufficientInstanceCapacity, SpotMaxPriceTooLow, ...); a fatal error
  aborts without downgrading.
- New output market-type-used reports the realized market (spot|on-demand).
- spot-max-price validated as a positive decimal at config parse.

Tests: buildMarketOptions (one-time/terminate/MaxPrice), buildMarketPlan,
launchAcrossMarkets (spot success, capacity fallback exactly once, price
fallback, fail-mode propagation, fatal abort), config validation (159 tests
total). README "Saving costs with spot" section with the interruption trade-off,
inputs/outputs tables, and action.yml descriptions.

Closes #39

Signed-off-by: kurok <22548029+kurok@users.noreply.github.com>
@kurok kurok merged commit 2c69b8a into main Jul 2, 2026
5 checks passed
@kurok kurok deleted the feat/spot-support branch July 2, 2026 19:02
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.

Spot instance support with on-demand fallback (market-type input)

1 participant