@serfab/cadre-core 1.16.0 → 1.18.0
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 +4 -3
- package/dist/bootstrap-peer-store-file.js +1 -1
- package/dist/bootstrap-peer-store.d.ts +1 -1
- package/dist/bootstrap-peer-store.js +4 -4
- package/dist/cadre-invite-protocol.d.ts +81 -142
- package/dist/cadre-invite-protocol.js +168 -458
- package/dist/cadre-invite-protocol.js.map +1 -1
- package/dist/cadre-join-request.d.ts +15 -2
- package/dist/cadre-join-request.js +22 -3
- package/dist/cadre-join-request.js.map +1 -1
- package/dist/cadre-node.d.ts +1089 -475
- package/dist/cadre-node.js +2170 -1037
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-authorization.d.ts +36 -14
- package/dist/control-authorization.js +20 -3
- package/dist/control-authorization.js.map +1 -1
- package/dist/control-cohort.d.ts +88 -32
- package/dist/control-cohort.js +91 -33
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +856 -318
- package/dist/control-database.js +1422 -701
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +46 -43
- package/dist/control-formation-recorder.js +77 -78
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-protocol-guard.d.ts +11 -4
- package/dist/control-protocol-guard.js +20 -5
- package/dist/control-protocol-guard.js.map +1 -1
- package/dist/control-schema-version.d.ts +97 -0
- package/dist/control-schema-version.js +225 -0
- package/dist/control-schema-version.js.map +1 -0
- package/dist/control-schema.d.ts +45 -5
- package/dist/control-schema.js +262 -78
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +45 -10
- package/dist/control-write-retry.js +92 -22
- package/dist/control-write-retry.js.map +1 -1
- package/dist/delegate-admission.d.ts +13 -0
- package/dist/delegate-admission.js +27 -0
- package/dist/delegate-admission.js.map +1 -1
- package/dist/ed25519-key.d.ts +10 -7
- package/dist/ed25519-key.js +23 -20
- package/dist/ed25519-key.js.map +1 -1
- package/dist/edge-node/config.d.ts +122 -0
- package/dist/edge-node/config.js +199 -0
- package/dist/edge-node/config.js.map +1 -0
- package/dist/edge-node/dissolve.d.ts +95 -0
- package/dist/edge-node/dissolve.js +184 -0
- package/dist/edge-node/dissolve.js.map +1 -0
- package/dist/edge-node/edge-join.d.ts +44 -0
- package/dist/edge-node/edge-join.js +227 -0
- package/dist/edge-node/edge-join.js.map +1 -0
- package/dist/edge-node/edge-node.d.ts +295 -0
- package/dist/edge-node/edge-node.js +704 -0
- package/dist/edge-node/edge-node.js.map +1 -0
- package/dist/edge-node/index.d.ts +18 -0
- package/dist/edge-node/index.js +18 -0
- package/dist/edge-node/index.js.map +1 -0
- package/dist/edge-node/join-credential.d.ts +11 -0
- package/dist/edge-node/join-credential.js +11 -0
- package/dist/edge-node/join-credential.js.map +1 -0
- package/dist/edge-node/lazy-raw-storage.d.ts +40 -0
- package/dist/edge-node/lazy-raw-storage.js +134 -0
- package/dist/edge-node/lazy-raw-storage.js.map +1 -0
- package/dist/edge-node/node-local.d.ts +60 -0
- package/dist/edge-node/node-local.js +58 -0
- package/dist/edge-node/node-local.js.map +1 -0
- package/dist/edge-node/options.d.ts +83 -0
- package/dist/edge-node/options.js +110 -0
- package/dist/edge-node/options.js.map +1 -0
- package/dist/edge-node/owner-grant.d.ts +41 -0
- package/dist/edge-node/owner-grant.js +38 -0
- package/dist/edge-node/owner-grant.js.map +1 -0
- package/dist/edge-node/platform.d.ts +140 -0
- package/dist/edge-node/platform.js +12 -0
- package/dist/edge-node/platform.js.map +1 -0
- package/dist/edge-node/strand-move.d.ts +115 -0
- package/dist/edge-node/strand-move.js +223 -0
- package/dist/edge-node/strand-move.js.map +1 -0
- package/dist/edge-node/strands.d.ts +28 -0
- package/dist/edge-node/strands.js +60 -0
- package/dist/edge-node/strands.js.map +1 -0
- package/dist/enrolled-machine-store.d.ts +3 -3
- package/dist/enrolled-machine-store.js +3 -3
- package/dist/formation-token.d.ts +48 -0
- package/dist/formation-token.js +26 -0
- package/dist/formation-token.js.map +1 -0
- package/dist/index.d.ts +27 -17
- package/dist/index.js +39 -17
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +29 -12
- package/dist/joined-strand-store.js +66 -27
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/key-store.d.ts +9 -4
- package/dist/key-store.js +9 -4
- package/dist/key-store.js.map +1 -1
- package/dist/link-budget.d.ts +9 -7
- package/dist/link-budget.js +9 -7
- package/dist/link-budget.js.map +1 -1
- package/dist/machine-removal.d.ts +19 -39
- package/dist/machine-removal.js +24 -98
- package/dist/machine-removal.js.map +1 -1
- package/dist/member-redemption.d.ts +256 -0
- package/dist/member-redemption.js +490 -0
- package/dist/member-redemption.js.map +1 -0
- package/dist/membership-view.d.ts +91 -0
- package/dist/membership-view.js +110 -0
- package/dist/membership-view.js.map +1 -0
- package/dist/owner-anchor-sync.d.ts +4 -4
- package/dist/owner-anchor-sync.js +16 -15
- package/dist/owner-anchor-sync.js.map +1 -1
- package/dist/owner-grant-protocol.d.ts +251 -0
- package/dist/owner-grant-protocol.js +344 -0
- package/dist/owner-grant-protocol.js.map +1 -0
- package/dist/owner-key-export.d.ts +70 -0
- package/dist/owner-key-export.js +279 -0
- package/dist/owner-key-export.js.map +1 -0
- package/dist/owner-key-flows.d.ts +55 -0
- package/dist/owner-key-flows.js +60 -0
- package/dist/owner-key-flows.js.map +1 -0
- package/dist/owner-key-store.d.ts +31 -0
- package/dist/owner-key-store.js +81 -0
- package/dist/owner-key-store.js.map +1 -0
- package/dist/owner-keys.d.ts +78 -0
- package/dist/owner-keys.js +133 -0
- package/dist/owner-keys.js.map +1 -0
- package/dist/owner-signer.d.ts +54 -0
- package/dist/owner-signer.js +51 -0
- package/dist/owner-signer.js.map +1 -0
- package/dist/peer-addr-book.d.ts +10 -1
- package/dist/peer-addr-book.js +4 -3
- package/dist/peer-addr-book.js.map +1 -1
- package/dist/peer-authorization.d.ts +83 -18
- package/dist/peer-authorization.js +123 -53
- package/dist/peer-authorization.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +89 -20
- package/dist/peer-join-backfill.js +265 -108
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/pending-join-runner.d.ts +48 -18
- package/dist/pending-join-runner.js +74 -56
- package/dist/pending-join-runner.js.map +1 -1
- package/dist/provider/rent-node.js +1 -1
- package/dist/provider/rent-node.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +162 -133
- package/dist/seed-bootstrap.js +300 -283
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.js +4 -4
- package/dist/strand-addr-protocol.d.ts +4 -1
- package/dist/strand-addr-protocol.js +8 -2
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-cohort.d.ts +3 -0
- package/dist/strand-cohort.js.map +1 -1
- package/dist/strand-database.d.ts +24 -2
- package/dist/strand-database.js +29 -6
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +176 -88
- package/dist/strand-first-sync-gate.js +288 -121
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-deadlines.d.ts +9 -9
- package/dist/strand-formation-deadlines.js +9 -9
- package/dist/strand-formation-manager.d.ts +23 -17
- package/dist/strand-formation-manager.js +46 -44
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +5 -8
- package/dist/strand-formation-protocol.js +101 -16
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +27 -18
- package/dist/strand-instance-manager.js +119 -50
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-reconciler.d.ts +16 -13
- package/dist/strand-membership-reconciler.js +30 -22
- package/dist/strand-membership-reconciler.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +45 -22
- package/dist/strand-membership-writer.js +226 -131
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-move.d.ts +6 -5
- package/dist/strand-move.js +36 -32
- package/dist/strand-move.js.map +1 -1
- package/dist/strand-peer-redial.js +2 -3
- package/dist/strand-peer-redial.js.map +1 -1
- package/dist/strand-revocation-enforcer.d.ts +134 -60
- package/dist/strand-revocation-enforcer.js +144 -71
- package/dist/strand-revocation-enforcer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +50 -39
- package/dist/strand-solicitation.js +10 -3
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-watcher.d.ts +80 -13
- package/dist/strand-watcher.js +152 -48
- package/dist/strand-watcher.js.map +1 -1
- package/dist/table-change-watch.d.ts +63 -0
- package/dist/table-change-watch.js +209 -0
- package/dist/table-change-watch.js.map +1 -0
- package/dist/timeout-scheduler.d.ts +4 -3
- package/dist/timeout-scheduler.js +4 -3
- package/dist/timeout-scheduler.js.map +1 -1
- package/dist/types.d.ts +374 -150
- package/dist/types.js +4 -4
- package/dist/types.js.map +1 -1
- package/package.json +17 -8
- package/src/bootstrap-peer-store-file.ts +44 -44
- package/src/bootstrap-peer-store.ts +214 -214
- package/src/cadre-invite-protocol.ts +740 -1052
- package/src/cadre-join-request.ts +24 -3
- package/src/cadre-node.ts +2402 -1079
- package/src/control-authorization.ts +47 -14
- package/src/control-cohort.ts +204 -128
- package/src/control-database.ts +1749 -820
- package/src/control-formation-recorder.ts +359 -353
- package/src/control-protocol-guard.ts +23 -6
- package/src/control-schema-version.ts +301 -0
- package/src/control-schema.ts +273 -78
- package/src/control-write-retry.ts +641 -567
- package/src/delegate-admission.ts +351 -314
- package/src/ed25519-key.ts +174 -171
- package/src/edge-node/config.ts +277 -0
- package/src/edge-node/dissolve.ts +251 -0
- package/src/edge-node/edge-join.ts +319 -0
- package/src/edge-node/edge-node.ts +1045 -0
- package/src/edge-node/index.ts +59 -0
- package/src/edge-node/join-credential.ts +16 -0
- package/src/edge-node/lazy-raw-storage.ts +178 -0
- package/src/edge-node/node-local.ts +84 -0
- package/src/edge-node/options.ts +179 -0
- package/src/edge-node/owner-grant.ts +63 -0
- package/src/edge-node/platform.ts +151 -0
- package/src/edge-node/strand-move.ts +270 -0
- package/src/edge-node/strands.ts +72 -0
- package/src/enrolled-machine-store.ts +3 -3
- package/src/formation-token.ts +63 -0
- package/src/index.ts +899 -789
- package/src/joined-strand-store.ts +73 -28
- package/src/key-store.ts +10 -4
- package/src/link-budget.ts +9 -7
- package/src/machine-removal.ts +26 -111
- package/src/member-redemption.ts +649 -0
- package/src/membership-view.ts +144 -0
- package/src/owner-anchor-sync.ts +19 -18
- package/src/owner-grant-protocol.ts +547 -0
- package/src/owner-key-export.ts +348 -0
- package/src/owner-key-flows.ts +109 -0
- package/src/owner-key-store.ts +85 -0
- package/src/owner-keys.ts +178 -0
- package/src/owner-signer.ts +94 -0
- package/src/peer-addr-book.ts +4 -3
- package/src/peer-authorization.ts +558 -488
- package/src/peer-join-backfill.ts +971 -761
- package/src/pending-join-runner.ts +76 -53
- package/src/provider/rent-node.ts +1 -1
- package/src/seed-bootstrap.ts +343 -349
- package/src/seed-trust-policy.ts +4 -4
- package/src/strand-addr-protocol.ts +547 -538
- package/src/strand-cohort.ts +4 -0
- package/src/strand-database.ts +352 -319
- package/src/strand-first-sync-gate.ts +334 -133
- package/src/strand-formation-deadlines.ts +227 -227
- package/src/strand-formation-manager.ts +731 -725
- package/src/strand-formation-protocol.ts +122 -24
- package/src/strand-instance-manager.ts +2092 -2026
- package/src/strand-membership-reconciler.ts +33 -25
- package/src/strand-membership-writer.ts +2093 -1974
- package/src/strand-move.ts +50 -38
- package/src/strand-peer-redial.ts +2 -3
- package/src/strand-revocation-enforcer.ts +740 -654
- package/src/strand-solicitation.ts +61 -34
- package/src/strand-watcher.ts +175 -56
- package/src/table-change-watch.ts +285 -0
- package/src/timeout-scheduler.ts +29 -28
- package/src/types.ts +391 -152
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* is described in `docs/strands.md` → "Joining while the inviter is offline".
|
|
7
7
|
*
|
|
8
8
|
* `CadreNode` owns every side effect and hands this module plain functions
|
|
9
|
-
* ({@link PendingJoinRunnerDeps}): read the joins,
|
|
10
|
-
* an outcome, say whether this machine is an
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* ({@link PendingJoinRunnerDeps}): read the joins, hear a change to the tables they are read
|
|
10
|
+
* from, run one attempt (its own `formStrand`), write an outcome, say whether this machine is an
|
|
11
|
+
* owner, and the clock. This module owns the policy: when to read the joins, when to attempt,
|
|
12
|
+
* how to read an attempt's failure, and how to settle an outcome write that another machine's
|
|
13
|
+
* write beat.
|
|
13
14
|
*
|
|
14
15
|
* Only owner machines run it, because every pending-join write is owner-signed. Letting a
|
|
15
16
|
* machine without an owner key finish a join is `blocked/decide-non-owner-machine-completes-a-pending-join`;
|
|
@@ -30,12 +31,28 @@ import { PendingJoinChangedError, type JoinRequestFields, type PendingJoinFields
|
|
|
30
31
|
import { FormationPostApprovalError, FormationRejectedError, FormationUnreachableError } from './strand-formation-rejection.js';
|
|
31
32
|
import { formationDeadlines } from './strand-formation-deadlines.js';
|
|
32
33
|
import { MEMBERSHIP_INVITE_TTL_MS } from './strand-formation-manager.js';
|
|
34
|
+
import { scheduleRuns, type TableChangeWatch, type TableChangeWatchOptions } from './table-change-watch.js';
|
|
33
35
|
import { defaultTimeoutScheduler, type TimeoutScheduler } from './timeout-scheduler.js';
|
|
34
36
|
|
|
35
37
|
const log = debug('sereus:cadre:pending-join');
|
|
36
38
|
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
+
/**
|
|
40
|
+
* The longest an owner machine goes without re-reading the party's pending joins when no change
|
|
41
|
+
* to their tables is heard. It covers a change that arrives without a storage event, and the
|
|
42
|
+
* time-driven removal of a finished join, which lands up to this much late.
|
|
43
|
+
*
|
|
44
|
+
* NOTE: on a cadre larger than `CONTROL_REPLICATION_BREADTH` (16), a machine outside a join
|
|
45
|
+
* table's cohort hears no change event, so a dismissal or another machine's outcome reaches it
|
|
46
|
+
* up to this much late. The worst effect is one more attempt on a dismissed join, whose outcome
|
|
47
|
+
* write then finds the request gone, or a `token-spent` answer whose re-read adopts the other
|
|
48
|
+
* machine's outcome. A 30 s pass while any join is pending was declined: a join can stay pending
|
|
49
|
+
* for {@link MAX_PENDING_JOIN_MS}, and those reads are what this backstop removes. Revisit if a
|
|
50
|
+
* cadre above 16 machines is seen attempting dismissed joins.
|
|
51
|
+
*/
|
|
52
|
+
export const PENDING_JOIN_BACKSTOP_MS = 10 * 60_000;
|
|
53
|
+
|
|
54
|
+
/** How soon a pass runs again after one failed, or after an outcome write gave up to another machine's writes. */
|
|
55
|
+
const PENDING_JOIN_PASS_RETRY_MS = 30_000;
|
|
39
56
|
|
|
40
57
|
/** Ceiling on the wait between two attempts of one join on one machine, before jitter. */
|
|
41
58
|
export const PENDING_JOIN_MAX_BACKOFF_MS = 10 * 60_000;
|
|
@@ -52,7 +69,7 @@ const MAX_BACKGROUND_ATTEMPTS = 2;
|
|
|
52
69
|
/** Each retry delay is moved by up to this fraction either way, so machines that failed together do not retry together. */
|
|
53
70
|
const RETRY_JITTER = 0.2;
|
|
54
71
|
|
|
55
|
-
/** Re-read-and-rewrite rounds after another machine's write won, before
|
|
72
|
+
/** Re-read-and-rewrite rounds after another machine's write won, before a pass {@link PENDING_JOIN_PASS_RETRY_MS} later decides instead. */
|
|
56
73
|
const MAX_OUTCOME_WRITE_ROUNDS = 3;
|
|
57
74
|
|
|
58
75
|
type AttemptError = NonNullable<PendingJoinStatus['lastError']>;
|
|
@@ -68,6 +85,10 @@ export interface PendingJoinRunnerDeps {
|
|
|
68
85
|
/** Whether this machine may write pending joins now. Asked every pass. */
|
|
69
86
|
isOwner(): Promise<boolean>;
|
|
70
87
|
readRows(): Promise<PendingJoin[]>;
|
|
88
|
+
/** Subscribe `onChange` to the tables a pass reads. Absent: passes come from `start`, `kick`, retries and the backstop only (tests). */
|
|
89
|
+
watchChanges?(onChange: () => Promise<void>, options: TableChangeWatchOptions): TableChangeWatch;
|
|
90
|
+
/** Run a pass at least this long after the last one settled; default {@link PENDING_JOIN_BACKSTOP_MS}. */
|
|
91
|
+
backstopMs?: number;
|
|
71
92
|
readRow(id: string): Promise<PendingJoin | null>;
|
|
72
93
|
/** One formation attempt for the request's invitation and disclosure (`CadreNode.formStrand`). */
|
|
73
94
|
attempt(join: PendingJoin): Promise<FormStrandResult>;
|
|
@@ -77,7 +98,7 @@ export interface PendingJoinRunnerDeps {
|
|
|
77
98
|
rewrite(expectedStampId: string, next: PendingJoinFields): Promise<PendingJoin>;
|
|
78
99
|
/** `ControlDatabase.deletePendingJoin`, owner-signed. */
|
|
79
100
|
remove(id: string): Promise<boolean>;
|
|
80
|
-
/** Whether this machine
|
|
101
|
+
/** Whether this machine reaches no sibling now (`CadreNode.hasReachableControlSibling`), so a write it commits reaches no other machine. */
|
|
81
102
|
isAlone(): boolean;
|
|
82
103
|
/** The sApp the request's invitation names. */
|
|
83
104
|
sAppIdOf(join: PendingJoin): string;
|
|
@@ -231,7 +252,7 @@ function stableFraction(key: string): number {
|
|
|
231
252
|
|
|
232
253
|
export class PendingJoinRunner {
|
|
233
254
|
private readonly tracked = new Map<string, TrackedJoin>();
|
|
234
|
-
/** Joins whose latest write by this machine committed with no
|
|
255
|
+
/** Joins whose latest write by this machine committed with no sibling reachable: id → the request stamp written. */
|
|
235
256
|
private readonly writtenAlone = new Map<string, string>();
|
|
236
257
|
private readonly dueQueue: TrackedJoin[] = [];
|
|
237
258
|
private readonly scheduler: TimeoutScheduler;
|
|
@@ -242,9 +263,8 @@ export class PendingJoinRunner {
|
|
|
242
263
|
/** How long a `token-spent` answer waits before its confirming attempt: long enough for a sibling's `joined` write to replicate. */
|
|
243
264
|
private readonly spentConfirmDelayMs: number;
|
|
244
265
|
private running = false;
|
|
245
|
-
|
|
246
|
-
private
|
|
247
|
-
private passAgain = false;
|
|
266
|
+
/** Every pass runs on it, one at a time; present between {@link start} and {@link stop}. */
|
|
267
|
+
private watch: TableChangeWatch | null = null;
|
|
248
268
|
private backgroundAttempts = 0;
|
|
249
269
|
|
|
250
270
|
constructor(private readonly deps: PendingJoinRunnerDeps) {
|
|
@@ -256,11 +276,21 @@ export class PendingJoinRunner {
|
|
|
256
276
|
this.spentConfirmDelayMs = 2 * deadlines.sessionMs;
|
|
257
277
|
}
|
|
258
278
|
|
|
259
|
-
/**
|
|
279
|
+
/**
|
|
280
|
+
* Start passes: one at once, then one whenever a table a pass reads changes, and at the latest
|
|
281
|
+
* {@link PENDING_JOIN_BACKSTOP_MS} after the last. Throws when the change subscription cannot
|
|
282
|
+
* be made.
|
|
283
|
+
*
|
|
284
|
+
* NOTE: a pass from before a {@link stop} that is still in flight runs alongside the new
|
|
285
|
+
* watch's passes, since each watch keeps only its own runs to one at a time. `CadreNode` builds
|
|
286
|
+
* a fresh runner per start, so nothing restarts one; if something comes to, make that pass
|
|
287
|
+
* check which start it belongs to.
|
|
288
|
+
*/
|
|
260
289
|
start(): void {
|
|
261
290
|
if (this.running) return;
|
|
291
|
+
this.watch = this.subscribe();
|
|
262
292
|
this.running = true;
|
|
263
|
-
this.
|
|
293
|
+
this.watch.trigger(0);
|
|
264
294
|
}
|
|
265
295
|
|
|
266
296
|
/**
|
|
@@ -274,18 +304,21 @@ export class PendingJoinRunner {
|
|
|
274
304
|
*/
|
|
275
305
|
stop(): void {
|
|
276
306
|
this.running = false;
|
|
277
|
-
|
|
307
|
+
// A pass already in flight finishes; `running` keeps it from scheduling anything further.
|
|
308
|
+
this.watch?.dispose();
|
|
309
|
+
this.watch = null;
|
|
278
310
|
for (const entry of this.tracked.values()) this.cancelTimer(entry);
|
|
279
311
|
this.tracked.clear();
|
|
280
312
|
this.dueQueue.length = 0;
|
|
281
313
|
this.writtenAlone.clear();
|
|
282
314
|
}
|
|
283
315
|
|
|
284
|
-
/**
|
|
316
|
+
/**
|
|
317
|
+
* Run a pass now, for a change the watched tables do not show (this machine's owner signer was
|
|
318
|
+
* just wired). A pass in flight is followed by one more.
|
|
319
|
+
*/
|
|
285
320
|
kick(): void {
|
|
286
|
-
|
|
287
|
-
this.clearPollTimer();
|
|
288
|
-
void this.pass();
|
|
321
|
+
this.watch?.trigger(0);
|
|
289
322
|
}
|
|
290
323
|
|
|
291
324
|
/**
|
|
@@ -327,8 +360,8 @@ export class PendingJoinRunner {
|
|
|
327
360
|
|
|
328
361
|
/**
|
|
329
362
|
* Re-write, with identical content under a fresh stamp, each join this machine last wrote while
|
|
330
|
-
*
|
|
331
|
-
*
|
|
363
|
+
* no sibling was reachable, so the other machines receive it. Called on the control cohort's
|
|
364
|
+
* growth edge, when a sibling becomes reachable. A join someone wrote since is left alone.
|
|
332
365
|
*
|
|
333
366
|
* NOTE: in memory only, so a join written alone by a process that stopped before it reconnected
|
|
334
367
|
* reaches the party only with that join's next write. A sweep of every join this machine wrote,
|
|
@@ -359,41 +392,29 @@ export class PendingJoinRunner {
|
|
|
359
392
|
}
|
|
360
393
|
}
|
|
361
394
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
this.
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
395
|
+
/** The watch every pass runs on: the deps' change subscription, or a timer-only one. */
|
|
396
|
+
private subscribe(): TableChangeWatch {
|
|
397
|
+
const onChange = (): Promise<void> => this.pass();
|
|
398
|
+
const options: TableChangeWatchOptions = {
|
|
399
|
+
label: 'pending-join',
|
|
400
|
+
backstopMs: this.deps.backstopMs ?? PENDING_JOIN_BACKSTOP_MS,
|
|
401
|
+
scheduler: this.scheduler,
|
|
402
|
+
};
|
|
403
|
+
return this.deps.watchChanges?.(onChange, options) ?? scheduleRuns(onChange, options);
|
|
369
404
|
}
|
|
370
405
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
this.
|
|
406
|
+
/** One pass; a failed one runs again {@link PENDING_JOIN_PASS_RETRY_MS} later. */
|
|
407
|
+
private async pass(): Promise<void> {
|
|
408
|
+
try {
|
|
409
|
+
await this.runPass();
|
|
410
|
+
} catch (error) {
|
|
411
|
+
log('pending-join pass failed; retried in 30 s: %s', errorText(error));
|
|
412
|
+
this.retryPass();
|
|
375
413
|
}
|
|
376
414
|
}
|
|
377
415
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (this.passInFlight) {
|
|
381
|
-
this.passAgain = true;
|
|
382
|
-
return this.passInFlight;
|
|
383
|
-
}
|
|
384
|
-
const run = this.runPass()
|
|
385
|
-
.catch((error: unknown) => log('pending-join pass failed; the next one retries: %s', errorText(error)))
|
|
386
|
-
.finally(() => {
|
|
387
|
-
this.passInFlight = null;
|
|
388
|
-
if (this.passAgain && this.running) {
|
|
389
|
-
this.passAgain = false;
|
|
390
|
-
void this.pass();
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
this.schedulePass(PENDING_JOIN_POLL_MS);
|
|
394
|
-
});
|
|
395
|
-
this.passInFlight = run;
|
|
396
|
-
return run;
|
|
416
|
+
private retryPass(): void {
|
|
417
|
+
this.watch?.trigger(PENDING_JOIN_PASS_RETRY_MS);
|
|
397
418
|
}
|
|
398
419
|
|
|
399
420
|
private async runPass(): Promise<void> {
|
|
@@ -415,7 +436,8 @@ export class PendingJoinRunner {
|
|
|
415
436
|
try {
|
|
416
437
|
await this.consider(join);
|
|
417
438
|
} catch (error) {
|
|
418
|
-
log('pending join %s: this pass could not handle it;
|
|
439
|
+
log('pending join %s: this pass could not handle it; retried in 30 s: %s', join.Id, errorText(error));
|
|
440
|
+
this.retryPass();
|
|
419
441
|
}
|
|
420
442
|
}
|
|
421
443
|
}
|
|
@@ -663,7 +685,8 @@ export class PendingJoinRunner {
|
|
|
663
685
|
}
|
|
664
686
|
expected = live!;
|
|
665
687
|
}
|
|
666
|
-
log('pending join %s: another machine kept changing the join;
|
|
688
|
+
log('pending join %s: another machine kept changing the join; a pass in 30 s decides', entry.row.Id);
|
|
689
|
+
this.retryPass();
|
|
667
690
|
}
|
|
668
691
|
|
|
669
692
|
private settle(join: PendingJoin): void {
|
|
@@ -143,7 +143,7 @@ async function requireOwner(node: RentingNode): Promise<void> {
|
|
|
143
143
|
|
|
144
144
|
async function rentByInvitation(node: RentingNode, client: ProviderClient, options: RentNodeOptions): Promise<RentNodeResult> {
|
|
145
145
|
report(options, 'inviting');
|
|
146
|
-
const { invitation, encoded } = await node.createCadreInvitation({
|
|
146
|
+
const { invitation, encoded } = await node.createCadreInvitation({ uses: 1, expiresInMs: RENTAL_INVITATION_TTL_MS });
|
|
147
147
|
report(options, 'creating');
|
|
148
148
|
let container;
|
|
149
149
|
try {
|