@molecule/api-deploy-rollout-fly
Provider bond · deploy-rollout · API (Node) · v2.0.1 · Apache-2.0
Fly Machines provider bond for @molecule/api-deploy-rollout: in-place restarts with a restore path and grow-then-shrink clones, over an injected flyctl runner.
npm install @molecule/api-deploy-rollout-flynpm · Source on GitHub · Implements @molecule/api-deploy-rollout
How it works
@molecule/api-deploy-rollout-fly is a provider bond on the API (Node) side: it implements the deploy-rollout core interface (@molecule/api-deploy-rollout) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { runInPlaceRollout, setProvider } from '@molecule/api-deploy-rollout'
import { provider } from '@molecule/api-deploy-rollout-default'
import { createFlyInPlaceProvider } from '@molecule/api-deploy-rollout-fly'
setProvider(provider)
await runInPlaceRollout({
provider: createFlyInPlaceProvider({
app: 'molecule-api',
isServing: (id) => probeMachine(id),
restore: (id) => clearPatchAndRestart(id),
}),
policy: { soakMs: 30_000 },
})Works with: @molecule/api-deploy-rollout
Reference
Fly Machines provider bonds for the deploy-rollout core.
In-place (restart the same Machines one at a time, with a restore path) and grow-then-shrink (clone a Machine beside the old set, retire the old one when the new one serves). Commands run through an injected runner, so tests need no Fly account.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { runInPlaceRollout, setProvider } from '@molecule/api-deploy-rollout'
import { provider } from '@molecule/api-deploy-rollout-default'
import { createFlyInPlaceProvider } from '@molecule/api-deploy-rollout-fly'
setProvider(provider)
await runInPlaceRollout({
provider: createFlyInPlaceProvider({
app: 'molecule-api',
isServing: (id) => probeMachine(id),
restore: (id) => clearPatchAndRestart(id),
}),
policy: { soakMs: 30_000 },
})
Type
provider
Installation
npm install @molecule/api-deploy-rollout-fly @molecule/api-deploy-rollout
API
Interfaces
FlyMachine
One Fly Machine, as the rollout needs to see it.
interface FlyMachine extends RolloutInstance {
/** The Machine's Fly state (`started`, `stopped`, …). */
state: string
/** The image the Machine runs, tag or digest form. */
imageRef: string | null
/** The Machine's configuration version (`instance_id`/`version`). */
version: string | null
/**
* The longest service-check grace period the Machine declares, in milliseconds.
*
* Fly reports a check inside its grace window as PASSING and can route traffic
* to a Machine that has not booted; a rolling restart must know the number to
* refuse it. Zero when the Machine's checks have no grace.
*/
gracePeriodMs: number
}
FlyCommandResult
The result of one flyctl invocation.
interface FlyCommandResult {
/** Exit status, or `null` when the process did not exit normally. */
status: number | null
/** Standard output. */
stdout: string
/** Standard error. */
stderr?: string
}
FlyMachinesOptions
Where and how the adapter reaches one Fly app.
interface FlyMachinesOptions {
/** The Fly app name. */
app: string
/** The runner; defaults to spawning the local `flyctl`. */
run?: FlyCommandRunner
}
FlyInPlaceOptions
What an in-place Fly rollout supplies that Fly itself does not know.
The adapter knows how to list, restart and start a Machine. Whether a Machine is SERVING, what "replace" means (a patch volume swap, a new image) and how to undo it are properties of the app being deployed, so the caller states them.
interface FlyInPlaceOptions extends FlyMachinesOptions {
/** Whether a Machine answers its readiness probe right now. */
isServing: (machineId: string) => Promise<boolean>
/**
* Change one Machine to the new build and leave it serving. Defaults to a restart
* that waits for the Machine to reach `started`.
*/
replace?: (machineId: string) => Promise<void>
/** Put one Machine back on the old build. */
restore?: (machineId: string) => Promise<void>
/** How long a restart may take to reach `started`. Defaults to 6 minutes. */
restartBudgetMs?: number
/** Sleep between state polls. Defaults to 5000 ms. */
pollMs?: number
}
FlyInstanceOptions
What a grow-then-shrink Fly rollout supplies that Fly itself does not know.
launch builds the Machine (image, volume, env, mounts) — that is the app's
deployment recipe. join/leave change whatever edge routes to the app; Fly's own
proxy balances by service, not by a caller-held set.
interface FlyInstanceOptions extends FlyMachinesOptions {
/** Create the Machine for `index` and resolve once it exists. */
launch: (index: number) => Promise<FlyMachine>
/** Whether a Machine answers its readiness probe right now. */
isServing: (machine: FlyMachine) => Promise<boolean>
/** Add a ready Machine to the caller's routable set. */
join?: (machine: FlyMachine) => Promise<void>
/** Remove a Machine from the caller's routable set. */
leave?: (machine: FlyMachine) => Promise<void>
/** How long `machine stop` may take. Defaults to 60 s. */
stopBudgetMs?: number
}
Types
FlyCommandRunner
Runs one flyctl command (without the leading flyctl).
type FlyCommandRunner = (args: string[]) => Promise<FlyCommandResult>
Functions
flyctlRunner(options)
A runner that spawns the local flyctl.
function flyctlRunner(options?: { cwd?: string }): FlyCommandRunner
options— The working directory flyctl should see.
Returns: The runner.
parseFlyDurationMs(value)
Parse a Fly duration (500ms, 5s, 1m0s, 1h30m) into milliseconds.
function parseFlyDurationMs(value: unknown): number
value— The configured value.
Returns: Milliseconds; 0 when absent or not a duration.
serviceCheckGraceMs(machine)
The longest service-check grace period any of a Machine's checks declares.
function serviceCheckGraceMs(machine: unknown): number
machine— One entry fromflyctl machine list --json.
Returns: Milliseconds; 0 when the Machine's checks have no grace.
parseFlyMachineList(json)
Parse flyctl machine list --app <app> --json into the facts a rollout needs.
function parseFlyMachineList(json: string): FlyMachine[]
json— The command's stdout.
Returns: Every Machine, in the order Fly listed them.
assertHomogeneousFlyMachines(machines)
Validate a Machine list as a rollout target set and return what to act on.
Every Machine must be started (a stopped one cannot be reached over SSH, and its patch volume would keep an older build), and all must run the SAME image. Configuration versions identify individual Machine instances, so a healthy rolling deployment has a different version on each Machine. Preserve those versions by id so callers can bind a patch to the Machine receiving it.
function assertHomogeneousFlyMachines(
machines: readonly FlyMachine[],
options?: { appName?: string },
): { ids: string[]; imageRef: string; machineVersions: Record<string, string> }
machines— Parsed Machines.
Returns: The target set's ids, shared image ref and each Machine's version.
listFlyMachines(options)
List one Fly app's Machines.
function listFlyMachines(options: FlyMachinesOptions): Promise<FlyMachine[]>
options— The app and the runner.
Returns: Every Machine the app has.
restartFlyMachine(options, machineId)
Restart one Machine and wait until it is started again.
A Machine that comes back stopped or suspended is started explicitly — Fly
occasionally parks one after a restart, and a role that leaves it parked turns a
successful roll into an outage.
function restartFlyMachine(
options: FlyMachinesOptions & { restartBudgetMs?: number; pollMs?: number },
machineId: string,
): Promise<boolean>
options— The app, the runner and the waits.machineId— The Machine to restart.
Returns: Whether it reached started inside the budget.
createFlyInPlaceProvider(options)
Create an in-place Fly Machines provider for the rollout core.
function createFlyInPlaceProvider(options: FlyInPlaceOptions): InPlaceInstanceProvider<FlyMachine>
options— The app, the runner, the readiness probe and the restore path.
Returns: An InPlaceInstanceProvider over Fly Machines.
createFlyInstanceProvider(options)
Create a grow-then-shrink Fly Machines provider for the rollout core.
create delegates to the caller's launch; drain asks Fly to stop the Machine
(a SIGTERM with a bounded wait), and destroy removes it.
function createFlyInstanceProvider(options: FlyInstanceOptions): InstanceProvider<FlyMachine>
options— The app, the runner and the app-specific operations.
Returns: An InstanceProvider over Fly Machines.
Core Interface
Implements @molecule/api-deploy-rollout interface.
Injection Notes
Requirements
Peer dependencies:
@molecule/api-deploy-rollout^1.0.0
Runtime Dependencies
-
@molecule/api-deploy-rollout -
parseFlyMachineListis the only JSON the adapter trusts. A Machine list that is not an array is an error, never an empty set. -
A mixed set is refused.
assertHomogeneousFlyMachinesrejects Machines on different images. Each Machine has its own configuration version; the returnedmachineVersionsmaps Machine ids to those versions. Bind each patch to its target's version so a later image or configuration update retires it. -
A restart that parks is started explicitly. A Machine that comes back
stopped/suspendedafter a restart is started, not left parked.