@zukhruf/single-flight 0.3.20 → 0.3.21
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/README.md +26 -17
- package/dist/client/flight-client.d.ts +9 -1
- package/dist/client/flight-client.d.ts.map +1 -1
- package/dist/client/flight-client.js +86 -16
- package/dist/client/flight-client.js.map +1 -1
- package/dist/coordinator/flight-coordinator.d.ts +24 -12
- package/dist/coordinator/flight-coordinator.d.ts.map +1 -1
- package/dist/coordinator/flight-coordinator.js +92 -143
- package/dist/coordinator/flight-coordinator.js.map +1 -1
- package/dist/coordinator/flight-server.d.ts +7 -7
- package/dist/coordinator/flight-server.d.ts.map +1 -1
- package/dist/coordinator/flight-server.js +7 -13
- package/dist/coordinator/flight-server.js.map +1 -1
- package/dist/coordinator/flight.d.ts +13 -2
- package/dist/coordinator/flight.d.ts.map +1 -1
- package/dist/coordinator/flight.js +20 -4
- package/dist/coordinator/flight.js.map +1 -1
- package/dist/coordinator/parked-runs.d.ts +26 -0
- package/dist/coordinator/parked-runs.d.ts.map +1 -0
- package/dist/coordinator/parked-runs.js +65 -0
- package/dist/coordinator/parked-runs.js.map +1 -0
- package/dist/coordinator/party.d.ts +1 -1
- package/dist/coordinator/party.d.ts.map +1 -1
- package/dist/coordinator/session.d.ts.map +1 -1
- package/dist/coordinator/session.js +6 -3
- package/dist/coordinator/session.js.map +1 -1
- package/dist/key-lock/key-hold.d.ts +16 -0
- package/dist/key-lock/key-hold.d.ts.map +1 -0
- package/dist/key-lock/key-hold.js +24 -0
- package/dist/key-lock/key-hold.js.map +1 -0
- package/dist/key-lock/key-locks.d.ts +35 -0
- package/dist/key-lock/key-locks.d.ts.map +1 -0
- package/dist/key-lock/key-locks.js +67 -0
- package/dist/key-lock/key-locks.js.map +1 -0
- package/dist/protocol/flight-protocol.d.ts +2 -2
- package/dist/protocol/flight-protocol.d.ts.map +1 -1
- package/dist/single-flight.d.ts +4 -12
- package/dist/single-flight.d.ts.map +1 -1
- package/dist/single-flight.js +36 -29
- package/dist/single-flight.js.map +1 -1
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ The lease that the work gets comes from `@zukhruf/lease`, and its token comes fr
|
|
|
70
70
|
|
|
71
71
|
## The directory
|
|
72
72
|
|
|
73
|
-
The directory is the local folder where the processes that share flights meet. Each process that uses a `SingleFlight` keeps
|
|
73
|
+
The directory is the local folder where the processes that share flights meet. Each process that uses a `SingleFlight` keeps three files and a folder there: `flight.lock`, `flight.epoch`, `flight.sock` and `execution-locks/`. The election of [`@zukhruf/election`](../election/README.md) claims `flight.lock` with a file lock, and records the epoch of the last term in `flight.epoch`. The folder `execution-locks/` has one file for each key that ever led: the key lock of that key, named by the SHA-256 of the key. The process that runs the work of a key holds a file lock on that file (see [When a process stops](#when-a-process-stops)). The files stay after the flights, so do not remove them while a process uses the directory. The journal of the claim is in memory, so a coordinator that stops leaves no `flight.lock-journal` file. All the processes that name the same directory are one group, and the callers of one key share a flight in that group only.
|
|
74
74
|
|
|
75
75
|
There is no default directory. One default would put each application on the host into one group, and unrelated applications that use the same key would join each other's flights. Give each group its own directory, for example a folder of your application's data.
|
|
76
76
|
|
|
@@ -87,15 +87,14 @@ All the processes of the directory take part in one election. The winner is the
|
|
|
87
87
|
The work gets the lease of the flight:
|
|
88
88
|
|
|
89
89
|
- `token`: a `FencingToken`. Its high 32 bits are the epoch of the coordinator's term, so a newer term always gives higher tokens.
|
|
90
|
-
- `signal`: it aborts with `LeaseLostError` when the flight is no longer the leader's. The `subject` of the error is the key. This occurs when the
|
|
90
|
+
- `signal`: it aborts with `LeaseLostError` when the flight is no longer the leader's, so its outcome reaches no joiner. The `subject` of the error is the key. This occurs when a new coordinator refuses the reassert of the leader, because it knows a newer flight of the key, or when this process cannot connect to a coordinator again.
|
|
91
91
|
|
|
92
|
-
| Option
|
|
93
|
-
|
|
|
94
|
-
| `directory`
|
|
95
|
-
| `codec`
|
|
96
|
-
| `graceWindow` | Milliseconds that a new coordinator starts no flight, so the leaders of the flights in progress can reassert them. It must be longer than a process takes to connect again. A coordinator after a clean shutdown has none. Defaults to `500`. |
|
|
92
|
+
| Option | What it does |
|
|
93
|
+
| ----------- | --------------------------------------------------------------------------------------------- |
|
|
94
|
+
| `directory` | The local folder where the processes of one group meet. See [The directory](#the-directory). |
|
|
95
|
+
| `codec` | Turns the value of a flight into text for the joiners, and back. See [The codec](#the-codec). |
|
|
97
96
|
|
|
98
|
-
`flights[Symbol.asyncDispose]()` waits until each landing of this process reached a coordinator, and then it disconnects. When this process is the coordinator, the other processes elect a new one.
|
|
97
|
+
`flights[Symbol.asyncDispose]()` waits until each landing of this process reached a coordinator, and then it disconnects. When this process is the coordinator, the other processes elect a new one. The work of a flight that this process leads continues, and this process keeps the key lock of that key until the work ends.
|
|
99
98
|
|
|
100
99
|
## The codec
|
|
101
100
|
|
|
@@ -165,17 +164,26 @@ Give a signal to stop the wait of one caller: `flights.run(key, work, { signal:
|
|
|
165
164
|
|
|
166
165
|
## When a process stops
|
|
167
166
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- **The
|
|
167
|
+
A leader keeps its flight while its process lives. Before its work starts, the leader takes a kernel lock on its key, the key lock. It frees the key lock only when its work settled and its flight needs nothing more from it: the coordinator acknowledged its landing, its lease was lost, or its `SingleFlight` closed. The kernel keeps the key lock while the process lives, also while the process is frozen, and it frees the key lock when the process dies. Thus no other process starts the work of the key beside it. [ADR 0010](./docs/adr/0010-a-leader-holds-a-kernel-lock-on-its-key-until-its-outcome-is-handed-over.md) tells why.
|
|
168
|
+
|
|
169
|
+
- **The process of a leader stops.** The coordinator tells each joiner that the flight is interrupted, and each joiner rejects with `FlightInterruptedError` at once. No joiner runs the work again. The kernel frees the key lock, and the next call of the key leads a new flight.
|
|
170
|
+
- **A leader disposes its `SingleFlight` while its work runs.** The coordinator interrupts the flight, because a disposed leader cannot send its outcome. Each joiner rejects with `FlightInterruptedError`. The work continues, and the leader keeps the key lock until the work ends. A call of the key in another process waits until then, and then it leads a new flight.
|
|
171
|
+
- **The coordinator stops or disposes.** The other processes elect a new coordinator, and it answers at once:
|
|
171
172
|
- Each leader reasserts its flight, and sends its landing again when it has one.
|
|
172
173
|
- Each joiner rejoins its flight by the flight's token, and it gets the outcome of that flight.
|
|
173
|
-
- A new call
|
|
174
|
-
-
|
|
175
|
-
- **A
|
|
174
|
+
- A new call of a key that no process holds leads or joins at once.
|
|
175
|
+
- A new call or a rejoin of a key whose key lock another process holds, while the new coordinator knows no flight of the key, waits. When the leader reasserts its flight, the call or the rejoin joins it. When the key lock frees first, the call leads, and the rejoin gets `FlightInterruptedError`.
|
|
176
|
+
- **A leader is frozen or busy, for example stopped by a debugger or in a long synchronous step.** It keeps its flight and its key lock. When the coordinator stops in that time, the calls of the key wait. When the leader continues, it reasserts its flight, and the calls that waited join it. When its process dies instead, the kernel frees the key lock, the joiners get `FlightInterruptedError`, and the next call leads.
|
|
177
|
+
- **A leader loses its lease.** This occurs only when a new coordinator refuses its reassert, because it knows a newer flight of the key, or when this process cannot connect to a coordinator again. The signal of the lease aborts with `LeaseLostError`, and the call of the leader rejects with that error. When the work throws its own error after the loss, the call rejects with a new `LeaseLostError`, and the error of the work is its `cause`. Thus `LeaseLostError` tells the leader that its outcome reached no joiner. Its joiners get `FlightInterruptedError`. The leader keeps the key lock until its work ends, so the next flight of the key runs after it, not beside it. [ADR 0007](./docs/adr/0007-a-work-error-after-a-lost-lease-rejects-with-leaselosterror.md) tells why.
|
|
178
|
+
- **A joiner's leader and the coordinator stop together.** The joiner gets `FlightInterruptedError` from the new coordinator. It never runs the work again.
|
|
176
179
|
|
|
177
180
|
A call that was on its way to a coordinator that stopped joined nothing. It goes again to the next coordinator as a new call. [ADR 0005](./docs/adr/0005-a-joiner-rejoins-its-flight-by-its-token.md) tells why.
|
|
178
181
|
|
|
182
|
+
### How long a call waits
|
|
183
|
+
|
|
184
|
+
- A call of a key waits with no limit while a process that lives holds the key lock, for example a frozen leader, or a leader whose work does not end. To set a limit, give a `signal`. A call of another key does not wait for it.
|
|
185
|
+
- Two flights of one key that follow each other wait about 10 ms between them. The leader frees the key lock only when it reads the acknowledgment of its landing, so the next call of the key waits for one more check of the key lock.
|
|
186
|
+
|
|
179
187
|
## Changes from 0.3.x
|
|
180
188
|
|
|
181
189
|
Version 0.3.13 to 0.3.15 had a pull design. These parts changed:
|
|
@@ -197,9 +205,9 @@ Version 0.3.13 to 0.3.15 had a pull design. These parts changed:
|
|
|
197
205
|
- [ADR 0006: The election and the connection are a copy of the mutex code](./docs/adr/0006-the-election-and-the-connection-are-a-copy-of-the-mutex-code.md)
|
|
198
206
|
- [ADR 0007: A work error after a lost lease rejects with LeaseLostError](./docs/adr/0007-a-work-error-after-a-lost-lease-rejects-with-leaselosterror.md)
|
|
199
207
|
- [ADR 0008: A connection closes only when its framing breaks](./docs/adr/0008-a-connection-closes-only-when-its-framing-breaks.md)
|
|
200
|
-
- [ADR
|
|
208
|
+
- [ADR 0010: A leader holds a kernel lock on its key until its outcome is handed over](./docs/adr/0010-a-leader-holds-a-kernel-lock-on-its-key-until-its-outcome-is-handed-over.md)
|
|
201
209
|
- [Code copied from the mutex](./docs/copied-from-mutex.md): each copied file, what changed, and why; the rules that the single flight shares with the mutex; and the code that is in two places inside the single flight.
|
|
202
|
-
- Superseded: [ADR 0001](./docs/adr/0001-a-joiner-follows-its-flight-record-without-acquiring-the-key.md)
|
|
210
|
+
- Superseded: [ADR 0001](./docs/adr/0001-a-joiner-follows-its-flight-record-without-acquiring-the-key.md), [ADR 0002](./docs/adr/0002-a-flight-that-all-callers-left-is-abandoned.md) and [ADR 0009](./docs/adr/0009-the-next-coordinator-skips-the-grace-window-after-a-clean-shutdown.md).
|
|
203
211
|
|
|
204
212
|
## Development
|
|
205
213
|
|
|
@@ -220,7 +228,8 @@ src/
|
|
|
220
228
|
codec.ts the Codec interface
|
|
221
229
|
errors.ts FlightFailedError, FlightInterruptedError
|
|
222
230
|
client/ the requests of one process: runs, leads, landings
|
|
223
|
-
coordinator/ the coordinator of one term: flights, sessions, its server
|
|
231
|
+
coordinator/ the coordinator of one term: flights, sessions, parked runs, its server
|
|
232
|
+
key-lock/ the key locks: the kernel lock on each key that a leader holds
|
|
224
233
|
protocol/ the messages between a process and its coordinator
|
|
225
234
|
connection/ the socket, the handshake and the supervisor (a copy); the election of the directory (@zukhruf/election)
|
|
226
235
|
shared/ the record check (a copy); file writes and the network directory check are in @zukhruf/fs
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FencingToken } from '@zukhruf/fencing';
|
|
2
2
|
import type { ConnectionSupervisor } from '../connection/connection-supervisor.ts';
|
|
3
|
+
import type { KeyLocks } from '../key-lock/key-locks.ts';
|
|
3
4
|
import { type FlightRequest, type Outcome } from '../protocol/flight-protocol.ts';
|
|
4
5
|
/** This process leads a flight: it runs the work and lands the outcome. */
|
|
5
6
|
export interface Lead {
|
|
@@ -8,6 +9,8 @@ export interface Lead {
|
|
|
8
9
|
readonly signal: AbortSignal;
|
|
9
10
|
/** Ends the flight with `outcome` for every joiner. Kept and sent again until a coordinator acknowledges it. */
|
|
10
11
|
land(outcome: Outcome): void;
|
|
12
|
+
/** The work settled. The key's lock waits for this, so call it on every path, also when the work never landed. */
|
|
13
|
+
ended(): void;
|
|
11
14
|
}
|
|
12
15
|
/** How the coordinator answered a run for good. */
|
|
13
16
|
export type Answer = {
|
|
@@ -19,6 +22,11 @@ export type Answer = {
|
|
|
19
22
|
} | {
|
|
20
23
|
kind: 'interrupted';
|
|
21
24
|
};
|
|
25
|
+
export interface FlightClientOptions {
|
|
26
|
+
locks: KeyLocks;
|
|
27
|
+
/** Whether no coordinator of a newer term than the one that minted `token` has been elected. */
|
|
28
|
+
isCurrentTerm(token: FencingToken): Promise<boolean>;
|
|
29
|
+
}
|
|
22
30
|
export interface RunRequest {
|
|
23
31
|
signal?: AbortSignal | undefined;
|
|
24
32
|
onJoin?: (() => void) | undefined;
|
|
@@ -32,7 +40,7 @@ export interface RunRequest {
|
|
|
32
40
|
*/
|
|
33
41
|
export declare class FlightClient {
|
|
34
42
|
#private;
|
|
35
|
-
constructor(link: ConnectionSupervisor<FlightRequest
|
|
43
|
+
constructor(link: ConnectionSupervisor<FlightRequest>, { locks, isCurrentTerm }: FlightClientOptions);
|
|
36
44
|
run(key: string, { signal, onJoin }: RunRequest): Promise<Answer>;
|
|
37
45
|
/**
|
|
38
46
|
* Disconnects for good, once every landing reached a coordinator: a landing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flight-client.d.ts","sourceRoot":"","sources":["../../src/client/flight-client.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"flight-client.d.ts","sourceRoot":"","sources":["../../src/client/flight-client.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAEnF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,OAAO,EAEb,MAAM,gCAAgC,CAAC;AAExC,2EAA2E;AAC3E,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,gHAAgH;IAChH,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,kHAAkH;IAClH,KAAK,IAAI,IAAI,CAAC;CACf;AAED,mDAAmD;AACnD,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,QAAQ,CAAC;IAChB,gGAAgG;IAChG,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACnC;AAiCD;;;;;;GAMG;AACH,qBAAa,YAAY;;gBAUrB,IAAI,EAAE,oBAAoB,CAAC,aAAa,CAAC,EACzC,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,mBAAmB;IAczC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BvE;;;;OAIG;IACG,KAAK;CA2OZ"}
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { untilAborted } from '@zukhruf/async';
|
|
3
3
|
import { FencingToken } from '@zukhruf/fencing';
|
|
4
4
|
import { LeaseController } from '@zukhruf/lease';
|
|
5
|
+
import { KeyHold } from "../key-lock/key-hold.js";
|
|
5
6
|
import { isFlightResponse, } from "../protocol/flight-protocol.js";
|
|
6
7
|
/**
|
|
7
8
|
* Sends runs to the coordinator over a supervised connection. When the
|
|
@@ -12,12 +13,16 @@ import { isFlightResponse, } from "../protocol/flight-protocol.js";
|
|
|
12
13
|
*/
|
|
13
14
|
export class FlightClient {
|
|
14
15
|
#link;
|
|
16
|
+
#locks;
|
|
17
|
+
#isCurrentTerm;
|
|
15
18
|
#pending = new Map();
|
|
16
19
|
#held = new Map();
|
|
17
20
|
/** Wakes `close` each time a flight this process leads is acknowledged or lost. */
|
|
18
21
|
#released = new Set();
|
|
19
|
-
constructor(link) {
|
|
22
|
+
constructor(link, { locks, isCurrentTerm }) {
|
|
20
23
|
this.#link = link;
|
|
24
|
+
this.#locks = locks;
|
|
25
|
+
this.#isCurrentTerm = isCurrentTerm;
|
|
21
26
|
link.on('connected', () => this.#resume());
|
|
22
27
|
// A message this client cannot read answers nothing it waits for.
|
|
23
28
|
link.on('message', (message) => {
|
|
@@ -37,7 +42,7 @@ export class FlightClient {
|
|
|
37
42
|
const pending = {
|
|
38
43
|
key,
|
|
39
44
|
onJoin,
|
|
40
|
-
delivery: 'queued',
|
|
45
|
+
delivery: { kind: 'queued' },
|
|
41
46
|
flight: undefined,
|
|
42
47
|
resolve,
|
|
43
48
|
reject,
|
|
@@ -50,8 +55,10 @@ export class FlightClient {
|
|
|
50
55
|
return await untilAborted(promise, signal);
|
|
51
56
|
}
|
|
52
57
|
catch (error) {
|
|
53
|
-
if (signal?.aborted)
|
|
58
|
+
if (signal?.aborted) {
|
|
54
59
|
this.#withdraw(id);
|
|
60
|
+
this.#abandon(id);
|
|
61
|
+
}
|
|
55
62
|
throw error;
|
|
56
63
|
}
|
|
57
64
|
}
|
|
@@ -68,6 +75,9 @@ export class FlightClient {
|
|
|
68
75
|
for (const id of [...this.#pending.keys()]) {
|
|
69
76
|
this.#take(id)?.reject(new Error('This single flight is closed.'));
|
|
70
77
|
}
|
|
78
|
+
// The coordinator interrupts the flights of a closed connection, so they need nothing more from this process.
|
|
79
|
+
for (const id of [...this.#held.keys()])
|
|
80
|
+
this.#release(id);
|
|
71
81
|
await closing;
|
|
72
82
|
}
|
|
73
83
|
#dispatch(id, pending) {
|
|
@@ -76,22 +86,72 @@ export class FlightClient {
|
|
|
76
86
|
? { op: 'run', id, key }
|
|
77
87
|
: { op: 'run', id, key, flight };
|
|
78
88
|
if (this.#link.send(request))
|
|
79
|
-
pending.delivery = 'sent';
|
|
89
|
+
pending.delivery = { kind: 'sent' };
|
|
80
90
|
}
|
|
81
91
|
/**
|
|
82
92
|
* The caller gave up. A run the coordinator may have heard is withdrawn;
|
|
83
93
|
* one that already leads is not pending any more, so its flight runs on.
|
|
94
|
+
* A run that waits for its key's lock leads at the coordinator, so the
|
|
95
|
+
* cancel interrupts that flight: its work never started.
|
|
84
96
|
*/
|
|
85
97
|
#withdraw(id) {
|
|
86
98
|
const pending = this.#take(id);
|
|
87
|
-
if (pending
|
|
99
|
+
if (pending && pending.delivery.kind !== 'queued') {
|
|
88
100
|
this.#link.send({ op: 'cancel', id });
|
|
101
|
+
}
|
|
89
102
|
}
|
|
90
|
-
|
|
103
|
+
/**
|
|
104
|
+
* The caller gave up although its run had led: the abort won the race with
|
|
105
|
+
* the answer, so nobody runs the work. The flight is interrupted, and the
|
|
106
|
+
* key's lock goes, instead of leading for the life of the process.
|
|
107
|
+
*/
|
|
108
|
+
#abandon(id) {
|
|
109
|
+
const held = this.#held.get(id);
|
|
110
|
+
if (!held)
|
|
111
|
+
return;
|
|
112
|
+
this.#link.send({ op: 'cancel', id });
|
|
113
|
+
this.#release(id);
|
|
114
|
+
held.hold.workEnded();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Told to lead: the run leads only once it holds its key's lock, so no
|
|
118
|
+
* other process runs the key's work beside it. A grant of an older term is
|
|
119
|
+
* stale: the coordinator that minted it is gone, and its successor may have
|
|
120
|
+
* let another run lead. That run goes again as a plain run.
|
|
121
|
+
*/
|
|
122
|
+
async #lock(id, pending, token, stop) {
|
|
123
|
+
try {
|
|
124
|
+
using locked = new DisposableStack();
|
|
125
|
+
locked.use(await this.#locks.acquire(pending.key, stop));
|
|
126
|
+
const current = await this.#isCurrentTerm(token);
|
|
127
|
+
if (stop.aborted)
|
|
128
|
+
return;
|
|
129
|
+
if (!current) {
|
|
130
|
+
locked.dispose();
|
|
131
|
+
pending.delivery = { kind: 'queued' };
|
|
132
|
+
this.#dispatch(id, pending);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.#take(id);
|
|
136
|
+
pending.resolve({
|
|
137
|
+
kind: 'lead',
|
|
138
|
+
lead: this.#hold(id, pending.key, token, new KeyHold(locked.move())),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
// An abort is the run's own end: it was answered, withdrawn or sent again.
|
|
143
|
+
if (stop.aborted)
|
|
144
|
+
return;
|
|
145
|
+
this.#take(id)?.reject(error);
|
|
146
|
+
this.#link.send({ op: 'cancel', id });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
#hold(id, key, token, hold) {
|
|
91
150
|
const held = {
|
|
92
151
|
key,
|
|
93
152
|
token,
|
|
94
153
|
lease: new LeaseController(key),
|
|
154
|
+
hold,
|
|
95
155
|
landing: undefined,
|
|
96
156
|
};
|
|
97
157
|
this.#held.set(id, held);
|
|
@@ -106,6 +166,7 @@ export class FlightClient {
|
|
|
106
166
|
this.#updateRef();
|
|
107
167
|
this.#link.send({ op: 'land', id, outcome });
|
|
108
168
|
},
|
|
169
|
+
ended: () => hold.workEnded(),
|
|
109
170
|
};
|
|
110
171
|
}
|
|
111
172
|
/** The flight of `id` is no longer this leader's, so its lease is told and nothing reasserts it. */
|
|
@@ -118,6 +179,7 @@ export class FlightClient {
|
|
|
118
179
|
}
|
|
119
180
|
/** The flight of `id` needs nothing more from this process. */
|
|
120
181
|
#release(id) {
|
|
182
|
+
this.#held.get(id)?.hold.flightEnded();
|
|
121
183
|
this.#held.delete(id);
|
|
122
184
|
this.#updateRef();
|
|
123
185
|
const waiting = [...this.#released];
|
|
@@ -129,14 +191,13 @@ export class FlightClient {
|
|
|
129
191
|
switch (response.op) {
|
|
130
192
|
case 'lead': {
|
|
131
193
|
// A run withdrawn meanwhile sent `cancel`, which interrupts the flight at the coordinator.
|
|
132
|
-
const pending = this.#
|
|
194
|
+
const pending = this.#pending.get(response.id);
|
|
133
195
|
if (!pending)
|
|
134
196
|
return;
|
|
135
|
-
const
|
|
136
|
-
pending.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
197
|
+
const stop = new AbortController();
|
|
198
|
+
pending.delivery = { kind: 'locking', stop };
|
|
199
|
+
// The first try of the lock is synchronous, here: only microtasks separate it from the work.
|
|
200
|
+
void this.#lock(response.id, pending, FencingToken.parse(response.token), stop.signal);
|
|
140
201
|
return;
|
|
141
202
|
}
|
|
142
203
|
case 'joined': {
|
|
@@ -195,14 +256,21 @@ export class FlightClient {
|
|
|
195
256
|
this.#link.send({ op: 'land', id, outcome: landing });
|
|
196
257
|
}
|
|
197
258
|
for (const [id, pending] of this.#pending) {
|
|
198
|
-
if (pending.delivery === 'queued')
|
|
259
|
+
if (pending.delivery.kind === 'queued')
|
|
199
260
|
this.#dispatch(id, pending);
|
|
200
261
|
}
|
|
201
262
|
}
|
|
202
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Nothing sent on the lost connection will be answered, so every run goes
|
|
265
|
+
* again on the next one. A run that waits for its key's lock had not led
|
|
266
|
+
* yet: the next coordinator may not know its flight, so it goes again too.
|
|
267
|
+
*/
|
|
203
268
|
#interrupt() {
|
|
204
|
-
for (const pending of this.#pending.values())
|
|
205
|
-
pending.delivery
|
|
269
|
+
for (const pending of this.#pending.values()) {
|
|
270
|
+
if (pending.delivery.kind === 'locking')
|
|
271
|
+
pending.delivery.stop.abort();
|
|
272
|
+
pending.delivery = { kind: 'queued' };
|
|
273
|
+
}
|
|
206
274
|
}
|
|
207
275
|
/** No coordinator heard the reassertions, so the flights this process leads may be interrupted already. */
|
|
208
276
|
#fail(error) {
|
|
@@ -216,6 +284,8 @@ export class FlightClient {
|
|
|
216
284
|
const pending = this.#pending.get(id);
|
|
217
285
|
if (!pending)
|
|
218
286
|
return undefined;
|
|
287
|
+
if (pending.delivery.kind === 'locking')
|
|
288
|
+
pending.delivery.stop.abort();
|
|
219
289
|
this.#pending.delete(id);
|
|
220
290
|
this.#updateRef();
|
|
221
291
|
return pending;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flight-client.js","sourceRoot":"","sources":["../../src/client/flight-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAIL,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"flight-client.js","sourceRoot":"","sources":["../../src/client/flight-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FencingToken, TokenSource } from '@zukhruf/fencing';
|
|
2
2
|
import type { Connection } from '../connection/connection.ts';
|
|
3
|
+
import type { KeyLocks } from '../key-lock/key-locks.ts';
|
|
3
4
|
import type { FlightResponse, Outcome } from '../protocol/flight-protocol.ts';
|
|
4
5
|
import { Flight } from './flight.ts';
|
|
5
6
|
import type { Party } from './party.ts';
|
|
@@ -7,29 +8,40 @@ export interface FlightCoordinatorOptions {
|
|
|
7
8
|
/** Mints the lease token of each flight this coordinator starts. */
|
|
8
9
|
tokens: TokenSource;
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* earlier coordinator can have left a flight in progress.
|
|
11
|
+
* The kernel locks on the keys. A process that holds a key's lock runs its
|
|
12
|
+
* work, whether this coordinator knows that flight or not.
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
locks: KeyLocks;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Coordinates the flights of one term. A run leads a new flight of its key, or
|
|
18
18
|
* joins the flight of that key in progress, in one step, so two runs never
|
|
19
19
|
* both lead. The outcome is pushed to every joiner as soon as it lands.
|
|
20
|
+
*
|
|
21
|
+
* A key whose lock another process holds, while no flight of it is known
|
|
22
|
+
* here, runs the work of a leader that has not reasserted its flight yet, so
|
|
23
|
+
* its runs and rejoins wait for that flight or for the lock to free. A leader
|
|
24
|
+
* keeps its flight while its process lives.
|
|
20
25
|
*/
|
|
21
26
|
export declare class FlightCoordinator {
|
|
22
27
|
#private;
|
|
23
|
-
constructor({ tokens,
|
|
24
|
-
/**
|
|
25
|
-
* Whether the next coordinator would find nothing to recover: no flight is
|
|
26
|
-
* in progress, and the grace window is over or there was none.
|
|
27
|
-
*/
|
|
28
|
-
get leavesNothingToRecover(): boolean;
|
|
28
|
+
constructor({ tokens, locks }: FlightCoordinatorOptions);
|
|
29
29
|
serve(connection: Connection<FlightResponse>): void;
|
|
30
|
+
/** Stops watching the locks of the keys whose runs wait. */
|
|
31
|
+
close(): void;
|
|
32
|
+
/** Rejects only when no token can be minted. */
|
|
30
33
|
run(party: Party, key: string): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
|
|
34
|
+
/**
|
|
35
|
+
* A joiner that lost its connection, back for the flight it joined: it never
|
|
36
|
+
* leads, so its work never runs twice. A rejoin joins only its own flight;
|
|
37
|
+
* any other answer could be a second run of the work.
|
|
38
|
+
*/
|
|
39
|
+
rejoin(party: Party, key: string, flight: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* A leader claims its flight again after its connection was lost. The same
|
|
42
|
+
* flight, through a new connection, stays one flight with its joiners. For
|
|
43
|
+
* two flights of one key, the newer token wins, and the older flight is lost.
|
|
44
|
+
*/
|
|
33
45
|
reassert(party: Party, key: string, token: FencingToken): void;
|
|
34
46
|
land(flight: Flight, outcome: Outcome): void;
|
|
35
47
|
/** The leader withdrew or its connection is gone. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flight-coordinator.d.ts","sourceRoot":"","sources":["../../src/coordinator/flight-coordinator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"flight-coordinator.d.ts","sourceRoot":"","sources":["../../src/coordinator/flight-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,MAAM,EAAE,WAAW,CAAC;IACpB;;;OAGG;IACH,KAAK,EAAE,QAAQ,CAAC;CACjB;AAQD;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;;gBAShB,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,wBAAwB;IAMvD,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,IAAI;IAInD,4DAA4D;IAC5D,KAAK,IAAI,IAAI;IAIb,gDAAgD;IAC1C,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM;IAKnC;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAevD;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAe9D,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAKrC,qDAAqD;IACrD,SAAS,CAAC,MAAM,EAAE,MAAM;CAwDzB"}
|