@parcha/pi-durable-disk 0.1.0-beta.13 → 0.1.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +262 -0
- package/README.md +281 -47
- package/dist/app.d.ts +5 -1
- package/dist/claim.d.ts +51 -3
- package/dist/claim.js +157 -17
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +112 -47
- package/dist/commands.d.ts +4 -1
- package/dist/commands.js +48 -90
- package/dist/confine.d.ts +36 -7
- package/dist/confine.js +125 -18
- package/dist/env.d.ts +7 -22
- package/dist/env.js +25 -60
- package/dist/errors.d.ts +2 -1
- package/dist/fork.d.ts +23 -0
- package/dist/fork.js +103 -3
- package/dist/hosts/attempt-env.d.ts +3 -0
- package/dist/hosts/attempt-env.js +15 -0
- package/dist/hosts/daytona-launch.d.ts +3 -1
- package/dist/hosts/daytona-launch.js +35 -12
- package/dist/hosts/daytona.d.ts +2 -2
- package/dist/hosts/daytona.js +48 -5
- package/dist/hosts/docker.d.ts +2 -2
- package/dist/hosts/docker.js +22 -5
- package/dist/hosts/local-host.d.ts +9 -3
- package/dist/hosts/local-host.js +59 -22
- package/dist/index.d.ts +35 -16
- package/dist/index.js +27 -16
- package/dist/internals.d.ts +3 -0
- package/dist/internals.js +6 -0
- package/dist/lease.d.ts +4 -1
- package/dist/lease.js +2 -0
- package/dist/local-run.js +3 -2
- package/dist/place.d.ts +190 -0
- package/dist/place.js +526 -0
- package/dist/process-table.d.ts +38 -0
- package/dist/process-table.js +158 -0
- package/dist/run.d.ts +61 -10
- package/dist/run.js +69 -33
- package/dist/status.d.ts +19 -3
- package/dist/status.js +25 -13
- package/dist/store.d.ts +14 -2
- package/dist/store.js +16 -4
- package/dist/supervise.d.ts +43 -1
- package/dist/supervise.js +26 -1
- package/dist/watchdog.d.ts +3 -1
- package/dist/watchdog.js +43 -12
- package/dist/with-claim.d.ts +63 -0
- package/dist/with-claim.js +325 -0
- package/package.json +9 -3
package/dist/lease.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export { EXIT_DATAERR, EXIT_SOFTWARE, LeaseLapsedError, openRunLease, OWNER_LOCK, RunError, StoreBehindSealError, storeHead, STORE_FILE } from "./run.js";
|
|
2
|
-
export type { LeaseOptions, OpenRunLeaseOptions, OpenStep, ReleaseStep, RunClaim, RunErrorCode, RunLease, StoreHeadSource } from "./run.js";
|
|
2
|
+
export type { LeaseOptions, OpenRunLeaseOptions, OpenStep, ReleaseStep, RunClaim, RunErrorCode, RunLease, RunSeed, RunSeedDir, StoreHeadSource } from "./run.js";
|
|
3
3
|
export * from "./errors.js";
|
|
4
4
|
export { assertPragmas, Fence, FencedDatabase, openArchilStore, PROFILE_PRAGMAS, StoreBusyError, StoreFencedError, StorePragmaError } from "./store.js";
|
|
5
5
|
export type { ArchilStore, OpenOptions, PragmaMismatch, Profile } from "./store.js";
|
|
6
6
|
export type { AcquireOptions, ArchilHost, Claim, RunRef, Unmounted } from "./claim.js";
|
|
7
7
|
export type { ClaimDir, PersistRecord, RunHolder, RunRecord, RunStatus } from "./status.js";
|
|
8
|
+
export { busyState, drain, leaseParkTarget, watchParking } from "./park.js";
|
|
9
|
+
export type { BusyState, DrainOptions, Parking, ParkOptions, ParkResult, ParkTarget } from "./park.js";
|
|
10
|
+
export type { DurableRun, RunEnv } from "./run.js";
|
package/dist/lease.js
CHANGED
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
export { EXIT_DATAERR, EXIT_SOFTWARE, LeaseLapsedError, openRunLease, OWNER_LOCK, RunError, StoreBehindSealError, storeHead, STORE_FILE } from "./run.js";
|
|
5
5
|
export * from "./errors.js";
|
|
6
6
|
export { assertPragmas, Fence, FencedDatabase, openArchilStore, PROFILE_PRAGMAS, StoreBusyError, StoreFencedError, StorePragmaError } from "./store.js";
|
|
7
|
+
// Parking, for a Harness the host opened over `openRunLease` (`leaseParkTarget`).
|
|
8
|
+
export { busyState, drain, leaseParkTarget, watchParking } from "./park.js";
|
package/dist/local-run.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
// store's own commits are made durable by SQLite, and work/ is the operating system's to flush; a power loss can lose what
|
|
9
9
|
// it had not written yet. It refuses once the claim is fenced, as a mount's does.
|
|
10
10
|
//
|
|
11
|
-
//
|
|
12
|
-
// (`
|
|
11
|
+
// On macOS, for development: it has no /proc/self/fd and no setpriv, so there the run's root is addressed by its path
|
|
12
|
+
// (openClaimDir's `byPath`), commands keep the user's rights, the file tools are confined by path (confine.ts), and the
|
|
13
|
+
// commands are recorded from ps (process-table.ts). The README's "On macOS" says what that costs.
|
|
13
14
|
import { mkdir } from "node:fs/promises";
|
|
14
15
|
import { join, resolve } from "node:path";
|
|
15
16
|
import { FencedError } from "./errors.js";
|
package/dist/place.d.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { Delegation } from "disk";
|
|
2
|
+
import { PdaError } from "./errors.js";
|
|
3
|
+
import { type RunRecord } from "./status.js";
|
|
4
|
+
import { type EnsureOptions, type HostDriver, type SupervisorControl } from "./supervise.js";
|
|
5
|
+
export type PlaceKill = "process" | "box";
|
|
6
|
+
/** The run's paths in the place: its id, its directory, and the `work` and `store` under it. */
|
|
7
|
+
export type PlacePaths = {
|
|
8
|
+
id: string;
|
|
9
|
+
root: string;
|
|
10
|
+
work: string;
|
|
11
|
+
store: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* How the run stood when a runner ended: the instance's own report, or `run.json` as it left it. `status` is the run's
|
|
15
|
+
* word: `complete` when it delivered, else `failed`.
|
|
16
|
+
*/
|
|
17
|
+
export type PlaceOutcome = {
|
|
18
|
+
status: string;
|
|
19
|
+
generation: number | null;
|
|
20
|
+
code?: string | null;
|
|
21
|
+
message?: string;
|
|
22
|
+
record?: unknown;
|
|
23
|
+
storeSha256?: string;
|
|
24
|
+
};
|
|
25
|
+
/** How a runner ended. `exit`: the exit code or signal (local), or the host's status (`stopped`, `failed`, `gone`) or `SIGKILL` when the place killed it (archil). */
|
|
26
|
+
export type PlaceExit = {
|
|
27
|
+
exit: number | string | null;
|
|
28
|
+
signal: string | null;
|
|
29
|
+
outcome?: PlaceOutcome;
|
|
30
|
+
stderr: string;
|
|
31
|
+
};
|
|
32
|
+
/** One instance of the run in a place. `epoch`: 1 on a plain directory; on a disk, the generation the instance opens. */
|
|
33
|
+
export type PlaceRunner = {
|
|
34
|
+
epoch: number;
|
|
35
|
+
pid?: number;
|
|
36
|
+
exited: Promise<PlaceExit>;
|
|
37
|
+
};
|
|
38
|
+
/** What a runner is handed: its number in the run, its environment, and for a place with a token, the attempt's mount token. */
|
|
39
|
+
export type RunnerOrder = {
|
|
40
|
+
gen: number;
|
|
41
|
+
env: Record<string, string>;
|
|
42
|
+
stdin?: string;
|
|
43
|
+
};
|
|
44
|
+
/** What the place reads of the run, the way it reads it: `run.json`, and on a disk the run's delegations. */
|
|
45
|
+
export type PlaceStatus = {
|
|
46
|
+
record: RunRecord | null;
|
|
47
|
+
delegations?: Pick<Delegation, "clientId" | "inodeId" | "path" | "isOrphaned" | "isPending">[];
|
|
48
|
+
};
|
|
49
|
+
/** What a recovery did. A takeover on a disk lists what it revoked, and `ms` is the whole of it (revoke and start). */
|
|
50
|
+
export type PlaceRecovery = {
|
|
51
|
+
runner: PlaceRunner;
|
|
52
|
+
restored?: {
|
|
53
|
+
checkpoint: string;
|
|
54
|
+
head: number;
|
|
55
|
+
};
|
|
56
|
+
replayed?: {
|
|
57
|
+
from: number;
|
|
58
|
+
to: number;
|
|
59
|
+
};
|
|
60
|
+
revoked?: Pick<Delegation, "clientId" | "inodeId" | "path" | "isOrphaned">[];
|
|
61
|
+
ms?: number;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* What a runner announces to its supervisor: a crossing it took, or a request to be killed at one (it parks there until
|
|
65
|
+
* the kill). `signals-failed` is the place's own last word when it could not read the requests: it ends the iterator,
|
|
66
|
+
* which never rejects. `code` is the failing read's error code when it has one (CONTROL_API_FAILED for a read that timed
|
|
67
|
+
* out), else SIGNALS_FAILED.
|
|
68
|
+
*/
|
|
69
|
+
export type PlaceSignal = {
|
|
70
|
+
kind: "crossing" | "kill-request";
|
|
71
|
+
crossing: {
|
|
72
|
+
point: string;
|
|
73
|
+
n: number;
|
|
74
|
+
pid?: number;
|
|
75
|
+
info?: Record<string, unknown>;
|
|
76
|
+
};
|
|
77
|
+
/** The attempt's nonce the runner wrote into its request, lifted out of `crossing`: the supervisor honors a kill request only with the nonce it minted for that attempt. */
|
|
78
|
+
nonce?: string;
|
|
79
|
+
} | {
|
|
80
|
+
kind: "signals-failed";
|
|
81
|
+
code: string;
|
|
82
|
+
message: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* What the supervisor hands a place factory: the run's paths as it computed them, how to take the boxes the run made,
|
|
86
|
+
* and where attempt n's runner writes its kill request (a file of the supervisor's machine).
|
|
87
|
+
*/
|
|
88
|
+
export type PlaceContext = {
|
|
89
|
+
paths: PlacePaths;
|
|
90
|
+
self?: string;
|
|
91
|
+
destroyBoxes?: () => void | Promise<void>;
|
|
92
|
+
requestFile?: (attempt: number) => string;
|
|
93
|
+
};
|
|
94
|
+
export interface Place {
|
|
95
|
+
/** `local` or `archil`, for the recording's lines. */
|
|
96
|
+
readonly name: string;
|
|
97
|
+
readonly paths: PlacePaths;
|
|
98
|
+
/** A place whose instance opens a claim mints each attempt's mount token: the supervisor passes it as the runner's stdin, never in argv or env. */
|
|
99
|
+
token?(attempt: number): string | undefined | Promise<string | undefined>;
|
|
100
|
+
/** What this place can lose. */
|
|
101
|
+
readonly kills: ReadonlyArray<PlaceKill>;
|
|
102
|
+
start(order: RunnerOrder): Promise<PlaceRunner>;
|
|
103
|
+
/**
|
|
104
|
+
* Where attempt `attempt`'s runner writes its kill request, as a path in the place (the supervisor puts it in the
|
|
105
|
+
* runner's order). A place with `signals` has it, and `signals(attempt)` reads what is written there.
|
|
106
|
+
*/
|
|
107
|
+
requestFile?(attempt: number): string;
|
|
108
|
+
/**
|
|
109
|
+
* The kill requests (and crossings) attempt `attempt`'s runner announces. The supervisor stops reading with `return()`
|
|
110
|
+
* once the runner has exited, and `return()` ends a pending `next()`.
|
|
111
|
+
*/
|
|
112
|
+
signals?(attempt: number): AsyncIterable<PlaceSignal>;
|
|
113
|
+
/** Takes the runner away abruptly, as a crash would. Safe on a runner that is already gone. */
|
|
114
|
+
kill(runner: PlaceRunner, kind: PlaceKill): Promise<void>;
|
|
115
|
+
status?(): Promise<PlaceStatus>;
|
|
116
|
+
/** Kills `last` if it still runs, then starts the next runner. */
|
|
117
|
+
recover(last: PlaceRunner, kind: PlaceKill, order: RunnerOrder): Promise<PlaceRecovery>;
|
|
118
|
+
checkpoint?(): Promise<{
|
|
119
|
+
taken: boolean;
|
|
120
|
+
heldBy?: string;
|
|
121
|
+
}>;
|
|
122
|
+
move?(to: Place): Promise<Record<string, unknown>>;
|
|
123
|
+
/** Lets the run go: stops what still runs (its commands too) and removes what the place made for it (tokens), never the run's directory. */
|
|
124
|
+
release(): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
export type PlaceErrorCode = "INVALID_ARGUMENT" | "HELD" | "START_TIMED_OUT" | "STATUS_FAILED" | "KILL_UNSUPPORTED" | "RELEASE_FAILED";
|
|
127
|
+
export declare class PlaceError extends PdaError {
|
|
128
|
+
constructor(code: PlaceErrorCode, message: string, options?: {
|
|
129
|
+
cause?: unknown;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
export interface LocalPlaceOptions {
|
|
133
|
+
/** The app module `run --app` loads. */
|
|
134
|
+
app: string;
|
|
135
|
+
/** The run's directory. Default: the context's `paths.root`. */
|
|
136
|
+
root?: string;
|
|
137
|
+
/** The instance program; `run` and its flags are appended. Default: this Node and the package's CLI. */
|
|
138
|
+
command?: string[];
|
|
139
|
+
/** Extra flags for `run` (heartbeat periods, a park threshold). */
|
|
140
|
+
runArgs?: string[];
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The run on a directory of this machine: each runner is `pi-durable-disk run --dir <root> --id <id> --app <app>`, a
|
|
144
|
+
* child in its own process group, with `{ PATH, ...order.env }` and nothing else of this process's environment. No disk,
|
|
145
|
+
* no key and no token. A process kill is SIGKILL to the group, and the next runner resumes the run from the directory; a
|
|
146
|
+
* box kill also takes the boxes the run made (`destroyBoxes`), so `kills` has `box` only when the context gives that.
|
|
147
|
+
* A runner's outcome is the instance's `{"outcome":...}` line on stdout, or, without one, `run.json` as it left it.
|
|
148
|
+
*/
|
|
149
|
+
export declare function localPlace(options: LocalPlaceOptions): (ctx: PlaceContext) => Place;
|
|
150
|
+
export interface ArchilPlaceOptions {
|
|
151
|
+
disk: string;
|
|
152
|
+
region: string;
|
|
153
|
+
/** The disk's control API (`archilControl`). The place holds it; no instance ever does. */
|
|
154
|
+
control: SupervisorControl;
|
|
155
|
+
/**
|
|
156
|
+
* The driver that runs the instance (`localHost`, `dockerHost`, `daytonaHost`), set up with the app the instance runs.
|
|
157
|
+
* Its `kill` and `kills` are the place's.
|
|
158
|
+
*/
|
|
159
|
+
host: HostDriver;
|
|
160
|
+
/** The run's id on the disk. Default: the context's `paths.id`. */
|
|
161
|
+
id?: string;
|
|
162
|
+
/** Where the driver mounts runs, for `paths`. Default: the driver's `mountRoot`, else /mnt/archil. */
|
|
163
|
+
mountRoot?: string;
|
|
164
|
+
/** More for each start's `ensureRunning`: the run directory's owner (`create`), token prefix and TTL, timeouts. */
|
|
165
|
+
ensure?: Omit<EnsureOptions, "control" | "demand" | "mountToken">;
|
|
166
|
+
/** How often a runner's host status is read. Default 1 s. */
|
|
167
|
+
pollMs?: number;
|
|
168
|
+
/** How long a start waits on a mount another start has in flight. Default 60 s. */
|
|
169
|
+
startTimeoutMs?: number;
|
|
170
|
+
/** How often `signals` reads the attempt's kill request over S3. Default 500 ms (the runner waits at its crossing). */
|
|
171
|
+
signalPollMs?: number;
|
|
172
|
+
/**
|
|
173
|
+
* How long those reads may fail (anything but a missing object) without a break before the iterator yields one
|
|
174
|
+
* `signals-failed` and ends. Default 60 s.
|
|
175
|
+
*/
|
|
176
|
+
signalFailMs?: number;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The run on an Archil disk, its instance run by a host driver. `token(attempt)` mints the attempt's mount token through
|
|
180
|
+
* the place's control, and the runner it is handed to mounts with it. A start is `ensureRunning` (it creates the run's
|
|
181
|
+
* directory with `ensure.create` and writes the start mark) with that token and the order's environment. A kill is the
|
|
182
|
+
* driver's `kill`: `process` or `box`, whichever the driver takes. A recovery is the takeover: the dead holder's
|
|
183
|
+
* delegations revoked (its lease counts as expired, since the place killed it) and the next instance started, which
|
|
184
|
+
* `revoked` and `ms` report. A runner writes its kill request in the run's directory (`requestFile`), and `signals` reads
|
|
185
|
+
* it over S3. A runner ends when the driver no longer reports it running, or when the place killed it; its
|
|
186
|
+
* outcome is `run.json` read over S3, with `code`, `message`, `record` and `storeSha256` from the detail of the last
|
|
187
|
+
* status the app set. `release` stops every instance it started and removes every token it minted; the run's directory
|
|
188
|
+
* stays (`deleteRunTree`).
|
|
189
|
+
*/
|
|
190
|
+
export declare function archilPlace(options: ArchilPlaceOptions): (ctx: PlaceContext) => Place;
|