Skip to content

Pricing & interruption

BigFleet ranks capacity with a locked cost formula:

effective_cost = price_per_hour + interruption_probability × penalty

So the OCI provider declares both honestly on every machine.

price_per_hour

Prices are live-refreshed from the public OCI price list (the cost-estimator API at apexapps.oracle.com/.../cetools, no credentials) into an in-memory table on a timer (--price-refresh, default 45m). List/Describe read that table — never a live pricing call on the hot path. The live price list is the source of truth.

prices.yaml (embedded, overridable with --prices-file) is the startup seed and fallback only: it primes prices before the first refresh, and stands in for any shape a refresh cannot price. It is no longer a frozen snapshot that silently drifts from the bill — the refresher keeps the table current, and the seed only backstops a fetch failure.

How shapes map onto OCI’s metered SKUs (part numbers):

  • Flexible shapes (name ends .Flex) are priced per-OCPU-hour + per-GB-hour, from the family’s OCPU and memory SKUs, times the launch OCPU/memory: price = ocpus × ocpu_rate + memory_gb × ram_rate.
  • Fixed GPU shapes use the per-GPU-hour SKU × the shape’s GPU count.
  • Fixed bare-metal Standard shapes (offered as on_demand) use the family’s per-OCPU/per-GB SKUs × the shape’s fixed OCPU/memory.
  • capacity_type: bare_metal reports 0 — it is held, already-paid-for capacity. (This is driven by the declared capacity type, not the shape prefix: a BM.* shape offered as on_demand is priced, not 0.)
  • Preemptible (spot) applies the table’s spot_discount (default 0.5; OCI Preemptible Instances are ~50% off on-demand) to the on-demand price.

Fail closed on unpriced

A shape that bills hourly (capacity_typebare_metal) must carry a non-zero price — emitting price_per_hour = 0 would rank it as free and attract every workload. So:

  • Startup is rejected if any hourly-billed offering would price at 0 (no live SKU and no prices.yaml entry). Add a prices.yaml entry or a SKU mapping.
  • A live rate of 0 (e.g. the always-free Ampere A1 SKUs, which the price list reports at 0) is skipped, so the shape keeps its non-zero seed value rather than being ranked free.
  • A genuine bare_metal lane is exempt — its 0 is honest (already paid for).

Staleness & observability

The refresher records its health so an operator can alert on a stale table:

  • bigfleet_oci_price_refresh_total{outcome} — success / error counts.
  • bigfleet_oci_price_last_success_timestamp_seconds — Unix time of the last successful refresh; staleness = time() - this.

A fetch error leaves the previous (live-or-seed) prices in place and logs a warning with the current staleness. The cost field feeds the engine’s relative ranking, so an approximate rate is acceptable, but the live refresh keeps it honest.

The prices.yaml seed pins a priced_at date and a source URL; refresh it occasionally so the fallback doesn’t drift, but the live list is what’s served.

interruption_probability

This is hourly, in [0, 1], provider-declared only (clusters can never override it), and it is correctness-critical: a preemptible machine that reports 0 looks free-and-safe and would be handed workloads it should never run. So a SPOT machine here never reports 0.

  • On-demand / bare metal: 0 (no provider-side interruption).
  • Preemptible (spot): OCI Preemptible Instances are genuinely reclaimed when capacity is needed (OCI emits a preemption-action event ahead of stop/terminate via the Events service). The provider publishes:
    • a forecast — a conservative per-shape hourly prior (a tunable table; scarcer / larger shapes carry a higher prior, default 0.10). This is what is published today for every preemptible machine, and it already satisfies the SPOT > 0 invariant.
    • a live observed escalation (enabled with --preemption-stream) — the provider consumes OCI preemption-action events (com.oraclecloud.computeapi.instancepreemptionaction) from an OCI Streaming stream and raises the affected machine’s probability toward 1.0 (0.99) about two minutes before the host is reclaimed, so the engine de-prioritises it before it disappears. Without the stream configured only the forecast prior is published (which already satisfies the SPOT > 0 invariant).

Because every preemptible offering declares a non-zero forecast, the conformance SPOT interruption_probability > 0 invariant holds by construction.

Wiring the live preemption stream

Point --preemption-stream at the OCID of an OCI Streaming stream, and create an OCI Events rule in the provider’s compartment whose condition matches event type com.oraclecloud.computeapi.instancepreemptionaction and whose action delivers to that stream (the OCI analogue of an AWS EventBridge rule → SQS queue). The provider reuses its existing --auth credentials to read the stream — no extra secret — and maps each event back to a BigFleet machine via the instance’s bigfleet-machine-id freeform tag (carried in the event payload, so no per-event API call). Leave the flag unset to publish the forecast prior only.