@zukhruf/election 0.3.20 → 0.3.22
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
CHANGED
|
@@ -51,6 +51,7 @@ next term: 2n
|
|
|
51
51
|
- `campaign({ timeout, signal })` resolves with a `Term`, or with `undefined` when another candidate still leads after `timeout` milliseconds. Without a `timeout`, it tries once. When `signal` aborts, it rejects with `signal.reason`, and a claim that it won meanwhile is given up.
|
|
52
52
|
- `claimFile` and `epochFile` are files in `directory`. Candidates with the same directory and the same file names are one group. Never delete `claimFile` while candidates run: a new file lets a second leader win.
|
|
53
53
|
- `epochFile` holds the epoch of the last term as decimal digits. When it holds other text, `campaign` rejects with a `SyntaxError` that names the file, gives the claim up, and does not change the file. An example is the empty file that `@zukhruf/mutex` 0.2.0 or earlier can leave after a power loss, because those versions did not sync the file to the disk. Thus the epochs never start again at 1, and each new term has a higher epoch than each earlier term.
|
|
54
|
+
- `lastEpoch()` resolves with the epoch of the last term in `epochFile`, or with `0n` when no term was won yet. It only reads the file. It does not campaign, it does not take the claim, and it does not create a file or the directory. Use it to find out if a value from an earlier term is stale, for example a fencing token that an old leader made with `EpochTokenSource`. A new term can start immediately after the read, so the answer can be old when you get it. When `epochFile` holds text that is not decimal digits, `lastEpoch()` rejects with the same `SyntaxError` as `campaign`. When it cannot read the file for another reason, it rejects with that error. It never answers `0n` for a file that it cannot read.
|
|
54
55
|
- A term that resigns clean writes a third file, `<claimFile>.clean`, beside `claimFile`. It holds the epoch of that term. The next term reads it and removes it.
|
|
55
56
|
- The directory must be on a local file system. On a network file system, `campaign` rejects with `NetworkDirectoryError`.
|
|
56
57
|
- `pollInterval` is the time between two tries, in milliseconds. It defaults to 10. A try never blocks the process.
|
|
@@ -61,7 +62,7 @@ A term is a lease on leadership. `Term` implements the `Lease` interface of [`@z
|
|
|
61
62
|
|
|
62
63
|
- `term.epoch` is the number of the term. Each epoch is below 2^31.
|
|
63
64
|
- `term.resign()` ends the term and gives the claim up. A second call waits for the first, and its options do nothing. `await using` resigns at the end of its scope.
|
|
64
|
-
- `term.resign({ clean: true })` records a clean shutdown for the next term, and then ends the term. Use it only when the leader leaves nothing for the next term to recover, for example no work in progress. A lost term records nothing, also with `clean`. When the record fails, the claim is freed, and `resign` rejects with that error.
|
|
65
|
+
- `term.resign({ clean: true })` records a clean shutdown for the next term, and then ends the term. Use it only when the leader leaves nothing for the next term to recover, for example no work in progress. A lost term records nothing, also with `clean`. When the record fails, the claim is freed, and `resign` rejects with that error. `@zukhruf/single-flight` no longer records a clean shutdown, because its coordinator has no grace window to skip ([its ADR 0010](../single-flight/docs/adr/0010-a-leader-holds-a-kernel-lock-on-its-key-until-its-outcome-is-handed-over.md)), but the option stays for other leaders (backlog #2647).
|
|
65
66
|
- `term.afterCleanShutdown` is `true` only when the term just before this one resigned clean. Then the new leader knows that it has nothing to recover. It is `false` after a crash, after a lost term, after a resign without `clean`, and for the first term.
|
|
66
67
|
- `term.signal` aborts with `LeaseLostError` when the term is lost while its leader still runs. The `subject` of the error is `'leadership'`, and its `cause` is the reason of the backend. The signal does not abort when the leader resigns.
|
|
67
68
|
|
|
@@ -25,6 +25,13 @@ export interface SqliteElectionOptions {
|
|
|
25
25
|
export declare class SqliteElection extends LeaderElection<FileLock> {
|
|
26
26
|
#private;
|
|
27
27
|
constructor({ directory, claimFile, epochFile, pollInterval, }: SqliteElectionOptions);
|
|
28
|
+
/**
|
|
29
|
+
* The epoch of the last term on disk, or 0 when no term was won yet. It
|
|
30
|
+
* only reads the epoch file: it does not campaign, take the claim, or
|
|
31
|
+
* create a file. A new term can begin as soon as it returns, so the answer
|
|
32
|
+
* can already be stale.
|
|
33
|
+
*/
|
|
34
|
+
lastEpoch(): Promise<bigint>;
|
|
28
35
|
protected open(): Promise<FileLock>;
|
|
29
36
|
protected tryClaim(claim: FileLock): Promise<Pick<Term, 'epoch' | 'afterCleanShutdown'> | undefined>;
|
|
30
37
|
/** The kernel holds the claim for as long as the process lives, so there is nothing to watch. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-election.d.ts","sourceRoot":"","sources":["../../src/sqlite/sqlite-election.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,QAAQ,EAKT,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,qBAAqB;IACpC,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,cAAc,CAAC,QAAQ,CAAC;;gBAM9C,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAiB,GAClB,EAAE,qBAAqB;
|
|
1
|
+
{"version":3,"file":"sqlite-election.d.ts","sourceRoot":"","sources":["../../src/sqlite/sqlite-election.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,QAAQ,EAKT,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,qBAAqB;IACpC,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,cAAc,CAAC,QAAQ,CAAC;;gBAM9C,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAiB,GAClB,EAAE,qBAAqB;IAQxB;;;;;OAKG;IACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;cAIZ,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC;cAMzB,QAAQ,CACtB,KAAK,EAAE,QAAQ,GACd,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,oBAAoB,CAAC,GAAG,SAAS,CAAC;IAgBlE,iGAAiG;IACjG,SAAS,CAAC,KAAK,IAAI,UAAU;IAI7B;;;;OAIG;cACa,mBAAmB,CACjC,MAAM,EAAE,QAAQ,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;cAIA,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;cAIvC,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtD"}
|
|
@@ -20,6 +20,15 @@ export class SqliteElection extends LeaderElection {
|
|
|
20
20
|
this.#epochPath = join(directory, epochFile);
|
|
21
21
|
this.#cleanShutdownPath = `${this.#claimPath}.clean`;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* The epoch of the last term on disk, or 0 when no term was won yet. It
|
|
25
|
+
* only reads the epoch file: it does not campaign, take the claim, or
|
|
26
|
+
* create a file. A new term can begin as soon as it returns, so the answer
|
|
27
|
+
* can already be stale.
|
|
28
|
+
*/
|
|
29
|
+
lastEpoch() {
|
|
30
|
+
return readEpoch(this.#epochPath);
|
|
31
|
+
}
|
|
23
32
|
async open() {
|
|
24
33
|
await assertLocalDirectory(this.#directory);
|
|
25
34
|
await mkdir(this.#directory, { recursive: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-election.js","sourceRoot":"","sources":["../../src/sqlite/sqlite-election.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sqlite-election.js","sourceRoot":"","sources":["../../src/sqlite/sqlite-election.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zukhruf/election",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.22",
|
|
4
4
|
"description": "Elect one leader among the processes that share a directory, with a term that ends when the leader dies and an epoch that grows with each term. Backends are subclasses of one campaign.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"sqlite"
|
|
22
22
|
],
|
|
23
23
|
"type": "module",
|
|
24
|
-
"types": "./dist/index.d.ts",
|
|
25
24
|
"exports": {
|
|
26
25
|
"./package.json": "./package.json",
|
|
27
26
|
".": {
|
|
@@ -41,8 +40,8 @@
|
|
|
41
40
|
"access": "public"
|
|
42
41
|
},
|
|
43
42
|
"dependencies": {
|
|
44
|
-
"@zukhruf/async": "^0.3.
|
|
45
|
-
"@zukhruf/fs": "^0.3.
|
|
46
|
-
"@zukhruf/lease": "^0.3.
|
|
43
|
+
"@zukhruf/async": "^0.3.22",
|
|
44
|
+
"@zukhruf/fs": "^0.3.22",
|
|
45
|
+
"@zukhruf/lease": "^0.3.22"
|
|
47
46
|
}
|
|
48
47
|
}
|