@amykit/plugin-slack 0.5.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 +61 -0
- package/dist/SlackApi.d.ts +67 -0
- package/dist/SlackApi.d.ts.map +1 -0
- package/dist/SlackApi.js +143 -0
- package/dist/SlackApi.js.map +1 -0
- package/dist/SlackConversation.d.ts +111 -0
- package/dist/SlackConversation.d.ts.map +1 -0
- package/dist/SlackConversation.js +504 -0
- package/dist/SlackConversation.js.map +1 -0
- package/dist/ThreadMap.d.ts +150 -0
- package/dist/ThreadMap.d.ts.map +1 -0
- package/dist/ThreadMap.js +444 -0
- package/dist/ThreadMap.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +43 -0
- package/dist/plugin.js.map +1 -0
- package/dist/secret.d.ts +13 -0
- package/dist/secret.d.ts.map +1 -0
- package/dist/secret.js +56 -0
- package/dist/secret.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One generation of a work item's thread: its root `ts` once Slack answered,
|
|
3
|
+
* the owner still posting it, or a tombstone left by whoever is forgetting it.
|
|
4
|
+
*/
|
|
5
|
+
export interface ThreadEntry {
|
|
6
|
+
channel?: string;
|
|
7
|
+
ts?: string;
|
|
8
|
+
/** When the first attempt of this chain was about to post. */
|
|
9
|
+
pendingSince?: number;
|
|
10
|
+
/** `<pid>:<uuid>` of the attempt still posting or forgetting; absent once released. */
|
|
11
|
+
owner?: string;
|
|
12
|
+
/** This work is being forgotten; nothing before it counts any more. */
|
|
13
|
+
tombstone?: true;
|
|
14
|
+
/** The root a tombstone is forgetting, so a retry can finish the job. */
|
|
15
|
+
covers?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ThreadMapOptions {
|
|
18
|
+
/** How long to wait for a live owner to finish before failing. */
|
|
19
|
+
maxWaitMs?: number;
|
|
20
|
+
pollMs?: number;
|
|
21
|
+
/** How long an owner's claim holds without being renewed. */
|
|
22
|
+
leaseMs?: number;
|
|
23
|
+
/** Told a root a newer one replaced, in another channel, so its files can go. */
|
|
24
|
+
onDisplaced?: (ts: string) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* What `start` is told: when an earlier attempt that may have posted began.
|
|
28
|
+
* It answers the root, and whether it posted it or found one already there.
|
|
29
|
+
*/
|
|
30
|
+
export type StartRoot = (recoverSince: number | undefined) => Promise<{
|
|
31
|
+
ts: string;
|
|
32
|
+
posted: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
/** Takes back a root this process posted after somebody else's replaced its claim. */
|
|
35
|
+
export type DiscardRoot = (ts: string) => Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* `workId → thread` on disk, shared by every process that mounts the plugin.
|
|
38
|
+
*
|
|
39
|
+
* The state directory is machine-wide, so several daemons use it at once.
|
|
40
|
+
* Each work item is a chain of numbered generations, `threads/<id>/<n>.json`,
|
|
41
|
+
* and a generation is created exclusively — written aside and linked into
|
|
42
|
+
* place — so exactly one process wins each number. Everything that changes
|
|
43
|
+
* what a chain means claims the next number first: posting a root, taking
|
|
44
|
+
* over from an owner that died, and forgetting the work, which leaves a
|
|
45
|
+
* tombstone and re-checks under it before removing anything.
|
|
46
|
+
*
|
|
47
|
+
* An owner holds its claim by lease: its generation's mtime is renewed while
|
|
48
|
+
* it works, and a claim whose lease ran out is dead even if some other
|
|
49
|
+
* process now has its pid.
|
|
50
|
+
*/
|
|
51
|
+
export declare class ThreadMap {
|
|
52
|
+
private readonly root;
|
|
53
|
+
private readonly maxWaitMs;
|
|
54
|
+
private readonly pollMs;
|
|
55
|
+
private readonly leaseMs;
|
|
56
|
+
private readonly onDisplaced;
|
|
57
|
+
/** Which work a root belongs to, as far as this process has seen. */
|
|
58
|
+
private readonly workOf;
|
|
59
|
+
constructor(directory: string, options?: ThreadMapOptions);
|
|
60
|
+
/**
|
|
61
|
+
* The thread this work already has in `channel`, if it has one.
|
|
62
|
+
*
|
|
63
|
+
* Asking counts as using it. The touch comes before looking for a
|
|
64
|
+
* tombstone, so a forget racing this either sees the touch and backs off,
|
|
65
|
+
* or left its tombstone first and this answers that there is no thread.
|
|
66
|
+
*/
|
|
67
|
+
known(workId: string, channel: string): string | undefined;
|
|
68
|
+
/** Marks the thread with this root as used, so reading its replies keeps it. */
|
|
69
|
+
used(ts: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* Forgets one work item's thread, returning the root it had, if any.
|
|
72
|
+
*
|
|
73
|
+
* The thread stays in Slack; only this machine's memory of it goes, so the
|
|
74
|
+
* next `open` for the same work starts a new one.
|
|
75
|
+
*/
|
|
76
|
+
forget(workId: string): string | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Forgets every settled thread nobody used since `cutoffMs`, returning the
|
|
79
|
+
* roots it forgot. An attempt whose owner still holds its lease is never
|
|
80
|
+
* pruned, however old.
|
|
81
|
+
*/
|
|
82
|
+
prune(cutoffMs: number): string[];
|
|
83
|
+
/** The work's thread in `channel`, posting its root through `start` only if nobody has. */
|
|
84
|
+
open(workId: string, channel: string, start: StartRoot, discard?: DiscardRoot): Promise<string>;
|
|
85
|
+
/** One look at the chain, and what the open does next because of it. */
|
|
86
|
+
private step;
|
|
87
|
+
/**
|
|
88
|
+
* Whether a released tombstone now stands above the claim this open lost,
|
|
89
|
+
* with no thread settled above that claim: a forget, not a winner.
|
|
90
|
+
*/
|
|
91
|
+
private forgottenSince;
|
|
92
|
+
/**
|
|
93
|
+
* Creates `n` exclusively and keeps it only if it is then the newest.
|
|
94
|
+
*
|
|
95
|
+
* Compaction frees numbers under a settled result, so an owner stalled past
|
|
96
|
+
* its lease can still win an exclusive create of its number after a taker
|
|
97
|
+
* published above it and cleared its claim. That create can only succeed
|
|
98
|
+
* once the taker's result exists, so the check after it always sees it.
|
|
99
|
+
*/
|
|
100
|
+
private publish;
|
|
101
|
+
/** Writes a known root again above a dead tombstone, clearing what is under it. */
|
|
102
|
+
private resettle;
|
|
103
|
+
/**
|
|
104
|
+
* A live owner still posting a root — for any channel: one for the old
|
|
105
|
+
* channel finishing after a newer generation settled would hand back a
|
|
106
|
+
* thread that is no longer current — or a live tombstone.
|
|
107
|
+
*/
|
|
108
|
+
private mustWaitOn;
|
|
109
|
+
/**
|
|
110
|
+
* One attempt at generation `next`: undefined when somebody else won the
|
|
111
|
+
* number; otherwise the root it posted or recovered, and whether its claim
|
|
112
|
+
* was still its own when the answer came back.
|
|
113
|
+
*/
|
|
114
|
+
private attempt;
|
|
115
|
+
/**
|
|
116
|
+
* Forgets a work item when `shouldGo` holds, asked again under a tombstone.
|
|
117
|
+
*
|
|
118
|
+
* The tombstone is the next generation, created exclusively, so nobody can
|
|
119
|
+
* post or take over while it stands, and it names the root it covers. If
|
|
120
|
+
* what it covers changed before the tombstone landed — touched, or taken —
|
|
121
|
+
* the forget backs off and removes only its own tombstone. A tombstone left
|
|
122
|
+
* by a forget that died is stepped over: the thread under it is the one
|
|
123
|
+
* decided on again, so a retry finishes the job it started.
|
|
124
|
+
*/
|
|
125
|
+
private retire;
|
|
126
|
+
private isLive;
|
|
127
|
+
/** The newest generation that is not a tombstone: the thread, or its attempt. */
|
|
128
|
+
private settled;
|
|
129
|
+
/** Every root recorded under generation `n`. */
|
|
130
|
+
private rootsBelow;
|
|
131
|
+
private current;
|
|
132
|
+
/** One generation, or nothing if it is gone; anything else is a real problem. */
|
|
133
|
+
private read;
|
|
134
|
+
private findWork;
|
|
135
|
+
private generations;
|
|
136
|
+
/**
|
|
137
|
+
* Exclusive: false when somebody else already holds this number, or when
|
|
138
|
+
* the chain's directory went away under a forget and has to be made again.
|
|
139
|
+
*/
|
|
140
|
+
private create;
|
|
141
|
+
/** Only by the tombstone's owner, whole and renamed into place. */
|
|
142
|
+
private release;
|
|
143
|
+
/** Generations under `n` are settled history once `n` is decided. */
|
|
144
|
+
private removeBelow;
|
|
145
|
+
private directoryOf;
|
|
146
|
+
private file;
|
|
147
|
+
}
|
|
148
|
+
/** Made if missing, and tightened if it was made looser before. */
|
|
149
|
+
export declare function privateDirectory(directory: string): void;
|
|
150
|
+
//# sourceMappingURL=ThreadMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadMap.d.ts","sourceRoot":"","sources":["../src/ThreadMap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* `workId → thread` on disk, shared by every process that mounts the plugin.
|
|
6
|
+
*
|
|
7
|
+
* The state directory is machine-wide, so several daemons use it at once.
|
|
8
|
+
* Each work item is a chain of numbered generations, `threads/<id>/<n>.json`,
|
|
9
|
+
* and a generation is created exclusively — written aside and linked into
|
|
10
|
+
* place — so exactly one process wins each number. Everything that changes
|
|
11
|
+
* what a chain means claims the next number first: posting a root, taking
|
|
12
|
+
* over from an owner that died, and forgetting the work, which leaves a
|
|
13
|
+
* tombstone and re-checks under it before removing anything.
|
|
14
|
+
*
|
|
15
|
+
* An owner holds its claim by lease: its generation's mtime is renewed while
|
|
16
|
+
* it works, and a claim whose lease ran out is dead even if some other
|
|
17
|
+
* process now has its pid.
|
|
18
|
+
*/
|
|
19
|
+
export class ThreadMap {
|
|
20
|
+
root;
|
|
21
|
+
maxWaitMs;
|
|
22
|
+
pollMs;
|
|
23
|
+
leaseMs;
|
|
24
|
+
onDisplaced;
|
|
25
|
+
/** Which work a root belongs to, as far as this process has seen. */
|
|
26
|
+
workOf = new Map();
|
|
27
|
+
constructor(directory, options = {}) {
|
|
28
|
+
this.root = path.join(directory, "threads");
|
|
29
|
+
// An owner may be waiting out Slack's one-a-minute limit several times.
|
|
30
|
+
this.maxWaitMs = options.maxWaitMs ?? 10 * 60_000;
|
|
31
|
+
this.pollMs = options.pollMs ?? 100;
|
|
32
|
+
this.leaseMs = options.leaseMs ?? 60_000;
|
|
33
|
+
this.onDisplaced = options.onDisplaced ?? (() => { });
|
|
34
|
+
// What threads a machine's work lives in is nobody else's to read.
|
|
35
|
+
privateDirectory(directory);
|
|
36
|
+
privateDirectory(this.root);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The thread this work already has in `channel`, if it has one.
|
|
40
|
+
*
|
|
41
|
+
* Asking counts as using it. The touch comes before looking for a
|
|
42
|
+
* tombstone, so a forget racing this either sees the touch and backs off,
|
|
43
|
+
* or left its tombstone first and this answers that there is no thread.
|
|
44
|
+
*/
|
|
45
|
+
known(workId, channel) {
|
|
46
|
+
requireId(workId);
|
|
47
|
+
const current = this.current(workId);
|
|
48
|
+
const ts = inChannel(current, channel)?.ts;
|
|
49
|
+
if (!ts)
|
|
50
|
+
return undefined;
|
|
51
|
+
touch(this.file(workId, current.n));
|
|
52
|
+
// Numbers come back after a forget, so the same number is not the same
|
|
53
|
+
// claim: it has to still carry the same root, and still be the newest.
|
|
54
|
+
if (this.read(workId, current.n)?.entry.ts !== ts)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (Math.max(0, ...this.generations(workId)) !== current.n)
|
|
57
|
+
return undefined;
|
|
58
|
+
this.workOf.set(ts, workId);
|
|
59
|
+
return ts;
|
|
60
|
+
}
|
|
61
|
+
/** Marks the thread with this root as used, so reading its replies keeps it. */
|
|
62
|
+
used(ts) {
|
|
63
|
+
const workId = this.workOf.get(ts) ?? this.findWork(ts);
|
|
64
|
+
if (!workId)
|
|
65
|
+
return;
|
|
66
|
+
// The generation carrying it, even under a tombstone: a forget's second
|
|
67
|
+
// look reads that generation, so a use now makes it back off.
|
|
68
|
+
const carrying = this.settled(workId);
|
|
69
|
+
if (carrying?.entry.ts === ts)
|
|
70
|
+
touch(this.file(workId, carrying.n));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Forgets one work item's thread, returning the root it had, if any.
|
|
74
|
+
*
|
|
75
|
+
* The thread stays in Slack; only this machine's memory of it goes, so the
|
|
76
|
+
* next `open` for the same work starts a new one.
|
|
77
|
+
*/
|
|
78
|
+
forget(workId) {
|
|
79
|
+
requireId(workId);
|
|
80
|
+
const outcome = this.retire(workId, (generation) => !this.isLive(generation));
|
|
81
|
+
if (outcome === "busy") {
|
|
82
|
+
// Its root may be reaching Slack right now; forgetting it would leave
|
|
83
|
+
// that root with no memory, and the next open would post a second.
|
|
84
|
+
throw new Error(`the thread for ${workId} is being opened right now; forget it once that finishes`);
|
|
85
|
+
}
|
|
86
|
+
return outcome;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Forgets every settled thread nobody used since `cutoffMs`, returning the
|
|
90
|
+
* roots it forgot. An attempt whose owner still holds its lease is never
|
|
91
|
+
* pruned, however old.
|
|
92
|
+
*/
|
|
93
|
+
prune(cutoffMs) {
|
|
94
|
+
const stale = (generation) => !generation.entry.tombstone && !this.isLive(generation) && generation.mtimeMs < cutoffMs;
|
|
95
|
+
const forgotten = [];
|
|
96
|
+
for (const name of entriesOf(this.root)) {
|
|
97
|
+
if (name.startsWith("."))
|
|
98
|
+
continue;
|
|
99
|
+
const outcome = this.retire(Buffer.from(name, "base64url").toString(), stale);
|
|
100
|
+
if (outcome && outcome !== "busy")
|
|
101
|
+
forgotten.push(outcome);
|
|
102
|
+
}
|
|
103
|
+
return forgotten;
|
|
104
|
+
}
|
|
105
|
+
/** The work's thread in `channel`, posting its root through `start` only if nobody has. */
|
|
106
|
+
async open(workId, channel, start, discard = async () => { }) {
|
|
107
|
+
requireId(workId);
|
|
108
|
+
const deadline = Date.now() + this.maxWaitMs;
|
|
109
|
+
// What this open has lost so far: the claim, to tell a winner from a
|
|
110
|
+
// forget, and a root it posted after losing it, taken back only once the
|
|
111
|
+
// winner's is known — and only if the winner did not settle on it.
|
|
112
|
+
const lost = {};
|
|
113
|
+
for (;;) {
|
|
114
|
+
const step = await this.step(workId, channel, start, lost);
|
|
115
|
+
if (step.kind === "wait") {
|
|
116
|
+
if (Date.now() >= deadline)
|
|
117
|
+
throw new Error(`another amy is still working on the thread for ${workId}`);
|
|
118
|
+
await new Promise((resolve) => setTimeout(resolve, this.pollMs));
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (step.kind === "again")
|
|
122
|
+
continue;
|
|
123
|
+
if (lost.posted && lost.posted !== step.ts)
|
|
124
|
+
await discard(lost.posted);
|
|
125
|
+
if (step.kind === "forgotten") {
|
|
126
|
+
throw new Error(`the thread for ${workId} was forgotten while it was being opened`);
|
|
127
|
+
}
|
|
128
|
+
return step.ts;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** One look at the chain, and what the open does next because of it. */
|
|
132
|
+
async step(workId, channel, start, lost) {
|
|
133
|
+
const top = this.current(workId);
|
|
134
|
+
// Forgotten while this open's post was out: nobody asked for a thread
|
|
135
|
+
// after that, so none is started — the late root is taken back.
|
|
136
|
+
if (lost.claim !== undefined && this.forgottenSince(workId, lost.claim, top))
|
|
137
|
+
return { kind: "forgotten" };
|
|
138
|
+
if (this.mustWaitOn(top))
|
|
139
|
+
return { kind: "wait" };
|
|
140
|
+
// Under a tombstone whose owner died mid-forget, the thread it covered
|
|
141
|
+
// is still the thread: adopted, not replaced by a second root.
|
|
142
|
+
const settled = this.settled(workId);
|
|
143
|
+
const entry = inChannel(settled, channel);
|
|
144
|
+
if (entry?.ts) {
|
|
145
|
+
if (top.n !== settled.n && !this.resettle(workId, top.n + 1, channel, entry.ts))
|
|
146
|
+
return { kind: "again" };
|
|
147
|
+
this.workOf.set(entry.ts, workId);
|
|
148
|
+
return { kind: "thread", ts: entry.ts };
|
|
149
|
+
}
|
|
150
|
+
const claim = (top?.n ?? 0) + 1;
|
|
151
|
+
const outcome = await this.attempt(workId, channel, claim, entry?.pendingSince, start);
|
|
152
|
+
if (outcome?.won)
|
|
153
|
+
return { kind: "thread", ts: outcome.ts };
|
|
154
|
+
if (outcome)
|
|
155
|
+
lost.claim = claim;
|
|
156
|
+
if (outcome?.posted)
|
|
157
|
+
lost.posted = outcome.ts;
|
|
158
|
+
return { kind: "again" };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Whether a released tombstone now stands above the claim this open lost,
|
|
162
|
+
* with no thread settled above that claim: a forget, not a winner.
|
|
163
|
+
*/
|
|
164
|
+
forgottenSince(workId, lostClaim, top) {
|
|
165
|
+
if (!top?.entry.tombstone || this.isLive(top) || top.n <= lostClaim)
|
|
166
|
+
return false;
|
|
167
|
+
const settled = this.settled(workId);
|
|
168
|
+
return !settled || settled.n < lostClaim;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Creates `n` exclusively and keeps it only if it is then the newest.
|
|
172
|
+
*
|
|
173
|
+
* Compaction frees numbers under a settled result, so an owner stalled past
|
|
174
|
+
* its lease can still win an exclusive create of its number after a taker
|
|
175
|
+
* published above it and cleared its claim. That create can only succeed
|
|
176
|
+
* once the taker's result exists, so the check after it always sees it.
|
|
177
|
+
*/
|
|
178
|
+
publish(workId, n, entry) {
|
|
179
|
+
if (!this.create(workId, n, entry))
|
|
180
|
+
return false;
|
|
181
|
+
if (Math.max(0, ...this.generations(workId)) === n)
|
|
182
|
+
return true;
|
|
183
|
+
fs.rmSync(this.file(workId, n), { force: true });
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
/** Writes a known root again above a dead tombstone, clearing what is under it. */
|
|
187
|
+
resettle(workId, next, channel, ts) {
|
|
188
|
+
if (!this.create(workId, next, { channel, ts }))
|
|
189
|
+
return false;
|
|
190
|
+
this.removeBelow(workId, next);
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* A live owner still posting a root — for any channel: one for the old
|
|
195
|
+
* channel finishing after a newer generation settled would hand back a
|
|
196
|
+
* thread that is no longer current — or a live tombstone.
|
|
197
|
+
*/
|
|
198
|
+
mustWaitOn(current) {
|
|
199
|
+
return current !== undefined && !current.entry.ts && this.isLive(current);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* One attempt at generation `next`: undefined when somebody else won the
|
|
203
|
+
* number; otherwise the root it posted or recovered, and whether its claim
|
|
204
|
+
* was still its own when the answer came back.
|
|
205
|
+
*/
|
|
206
|
+
async attempt(workId, channel, next, recoverSince, start) {
|
|
207
|
+
// Once, before the post: a failure reported later must not move it.
|
|
208
|
+
const pendingSince = recoverSince ?? Date.now();
|
|
209
|
+
const owner = `${process.pid}:${randomUUID()}`;
|
|
210
|
+
if (!this.create(workId, next, { channel, pendingSince, owner }))
|
|
211
|
+
return undefined;
|
|
212
|
+
const renew = setInterval(() => touch(this.file(workId, next)), Math.max(1, Math.floor(this.leaseMs / 4)));
|
|
213
|
+
renew.unref();
|
|
214
|
+
let ts;
|
|
215
|
+
let posted;
|
|
216
|
+
try {
|
|
217
|
+
({ ts, posted } = await start(recoverSince));
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
// Released as the next generation, not removed: Slack may have taken
|
|
221
|
+
// the root before the call failed, and the next attempt recovers from
|
|
222
|
+
// this instant. If the number is gone, somebody already moved on.
|
|
223
|
+
this.publish(workId, next + 1, { channel, pendingSince });
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
clearInterval(renew);
|
|
228
|
+
}
|
|
229
|
+
// Published as the next generation, created exclusively, never written
|
|
230
|
+
// over the claim: if a taker, a tombstone or anyone else took that number
|
|
231
|
+
// first, this claim was lost while the post was out. The open then reads
|
|
232
|
+
// what the newer claim settles on, and takes this root back only if it
|
|
233
|
+
// posted it and the winner did not recover that very root.
|
|
234
|
+
const result = next + 1;
|
|
235
|
+
if (!this.publish(workId, result, { channel, ts }))
|
|
236
|
+
return { ts, posted, won: false };
|
|
237
|
+
const displaced = this.rootsBelow(workId, result).filter((older) => older !== ts);
|
|
238
|
+
this.removeBelow(workId, result);
|
|
239
|
+
for (const older of displaced) {
|
|
240
|
+
this.workOf.delete(older);
|
|
241
|
+
this.onDisplaced(older);
|
|
242
|
+
}
|
|
243
|
+
this.workOf.set(ts, workId);
|
|
244
|
+
return { ts, posted, won: true };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Forgets a work item when `shouldGo` holds, asked again under a tombstone.
|
|
248
|
+
*
|
|
249
|
+
* The tombstone is the next generation, created exclusively, so nobody can
|
|
250
|
+
* post or take over while it stands, and it names the root it covers. If
|
|
251
|
+
* what it covers changed before the tombstone landed — touched, or taken —
|
|
252
|
+
* the forget backs off and removes only its own tombstone. A tombstone left
|
|
253
|
+
* by a forget that died is stepped over: the thread under it is the one
|
|
254
|
+
* decided on again, so a retry finishes the job it started.
|
|
255
|
+
*/
|
|
256
|
+
retire(workId, shouldGo) {
|
|
257
|
+
const top = this.current(workId);
|
|
258
|
+
if (!top)
|
|
259
|
+
return undefined;
|
|
260
|
+
if (this.isLive(top))
|
|
261
|
+
return "busy";
|
|
262
|
+
const subject = this.settled(workId);
|
|
263
|
+
// Nothing under a floor or a dead tombstone: nothing left to forget.
|
|
264
|
+
if (!subject)
|
|
265
|
+
return undefined;
|
|
266
|
+
if (!shouldGo(subject))
|
|
267
|
+
return "busy";
|
|
268
|
+
const tombstone = top.n + 1;
|
|
269
|
+
const claim = { tombstone: true, owner: `${process.pid}:${randomUUID()}`, covers: subject?.entry.ts };
|
|
270
|
+
if (!this.create(workId, tombstone, claim))
|
|
271
|
+
return "busy";
|
|
272
|
+
const covered = this.read(workId, subject.n);
|
|
273
|
+
if (!covered || !shouldGo(covered)) {
|
|
274
|
+
fs.rmSync(this.file(workId, tombstone), { force: true });
|
|
275
|
+
return "busy";
|
|
276
|
+
}
|
|
277
|
+
this.removeBelow(workId, tombstone);
|
|
278
|
+
// Kept, released, as the chain's floor: numbers never come back, so a
|
|
279
|
+
// request that outlived its claim can never publish over a newer one.
|
|
280
|
+
this.release(workId, tombstone, { tombstone: true, covers: covered.entry.ts });
|
|
281
|
+
const ts = covered.entry.ts;
|
|
282
|
+
if (ts)
|
|
283
|
+
this.workOf.delete(ts);
|
|
284
|
+
return ts;
|
|
285
|
+
}
|
|
286
|
+
isLive(generation) {
|
|
287
|
+
const owner = generation.entry.owner;
|
|
288
|
+
if (!owner)
|
|
289
|
+
return false;
|
|
290
|
+
return Date.now() - generation.mtimeMs < this.leaseMs && isAlive(pidOf(owner));
|
|
291
|
+
}
|
|
292
|
+
/** The newest generation that is not a tombstone: the thread, or its attempt. */
|
|
293
|
+
settled(workId) {
|
|
294
|
+
const numbers = this.generations(workId).sort((a, b) => b - a);
|
|
295
|
+
for (const n of numbers) {
|
|
296
|
+
const generation = this.read(workId, n);
|
|
297
|
+
if (generation && !generation.entry.tombstone)
|
|
298
|
+
return generation;
|
|
299
|
+
}
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
/** Every root recorded under generation `n`. */
|
|
303
|
+
rootsBelow(workId, n) {
|
|
304
|
+
return this.generations(workId)
|
|
305
|
+
.filter((older) => older < n)
|
|
306
|
+
.map((older) => this.read(workId, older)?.entry.ts)
|
|
307
|
+
.filter((ts) => ts !== undefined);
|
|
308
|
+
}
|
|
309
|
+
current(workId) {
|
|
310
|
+
const n = Math.max(0, ...this.generations(workId));
|
|
311
|
+
if (n === 0)
|
|
312
|
+
return undefined;
|
|
313
|
+
// Removed by the owner that superseded it between the listing and the read.
|
|
314
|
+
return this.read(workId, n) ?? this.current(workId);
|
|
315
|
+
}
|
|
316
|
+
/** One generation, or nothing if it is gone; anything else is a real problem. */
|
|
317
|
+
read(workId, n) {
|
|
318
|
+
const file = this.file(workId, n);
|
|
319
|
+
try {
|
|
320
|
+
const mtimeMs = fs.statSync(file).mtimeMs;
|
|
321
|
+
return { n, entry: JSON.parse(fs.readFileSync(file, "utf8")), mtimeMs };
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
if (error.code === "ENOENT")
|
|
325
|
+
return undefined;
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
findWork(ts) {
|
|
330
|
+
for (const name of entriesOf(this.root)) {
|
|
331
|
+
if (name.startsWith("."))
|
|
332
|
+
continue;
|
|
333
|
+
const workId = Buffer.from(name, "base64url").toString();
|
|
334
|
+
// The settled generation, not the top: under a tombstone, the thread
|
|
335
|
+
// it covers is still the one a held reference is using.
|
|
336
|
+
if (this.settled(workId)?.entry.ts === ts) {
|
|
337
|
+
this.workOf.set(ts, workId);
|
|
338
|
+
return workId;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return undefined;
|
|
342
|
+
}
|
|
343
|
+
generations(workId) {
|
|
344
|
+
return entriesOf(this.directoryOf(workId))
|
|
345
|
+
.map((name) => /^(\d+)\.json$/.exec(name)?.[1])
|
|
346
|
+
.filter((n) => n !== undefined)
|
|
347
|
+
.map(Number);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Exclusive: false when somebody else already holds this number, or when
|
|
351
|
+
* the chain's directory went away under a forget and has to be made again.
|
|
352
|
+
*/
|
|
353
|
+
create(workId, n, entry) {
|
|
354
|
+
privateDirectory(this.root);
|
|
355
|
+
// Staged outside the chain, so a forget can always remove an empty one.
|
|
356
|
+
const staged = path.join(this.root, `.${randomUUID()}.tmp`);
|
|
357
|
+
fs.writeFileSync(staged, JSON.stringify(entry), { mode: 0o600 });
|
|
358
|
+
try {
|
|
359
|
+
fs.mkdirSync(this.directoryOf(workId), { recursive: true, mode: 0o700 });
|
|
360
|
+
fs.linkSync(staged, this.file(workId, n));
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
const code = error.code;
|
|
365
|
+
if (code !== "EEXIST" && code !== "ENOENT")
|
|
366
|
+
throw error;
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
fs.rmSync(staged, { force: true });
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/** Only by the tombstone's owner, whole and renamed into place. */
|
|
374
|
+
release(workId, n, entry) {
|
|
375
|
+
const staged = path.join(this.root, `.${randomUUID()}.tmp`);
|
|
376
|
+
fs.writeFileSync(staged, JSON.stringify(entry), { mode: 0o600 });
|
|
377
|
+
fs.renameSync(staged, this.file(workId, n));
|
|
378
|
+
}
|
|
379
|
+
/** Generations under `n` are settled history once `n` is decided. */
|
|
380
|
+
removeBelow(workId, n) {
|
|
381
|
+
for (const older of this.generations(workId)) {
|
|
382
|
+
if (older < n)
|
|
383
|
+
fs.rmSync(this.file(workId, older), { force: true });
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
directoryOf(workId) {
|
|
387
|
+
return path.join(this.root, Buffer.from(workId).toString("base64url"));
|
|
388
|
+
}
|
|
389
|
+
file(workId, n) {
|
|
390
|
+
return path.join(this.directoryOf(workId), `${n}.json`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/** The generation's entry when it is a thread in `channel`, not a tombstone. */
|
|
394
|
+
function inChannel(current, channel) {
|
|
395
|
+
return current && !current.entry.tombstone && current.entry.channel === channel ? current.entry : undefined;
|
|
396
|
+
}
|
|
397
|
+
/** Made if missing, and tightened if it was made looser before. */
|
|
398
|
+
export function privateDirectory(directory) {
|
|
399
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
400
|
+
fs.chmodSync(directory, 0o700);
|
|
401
|
+
}
|
|
402
|
+
/** A directory's names, or none if a forget removed it a moment ago. */
|
|
403
|
+
function entriesOf(directory) {
|
|
404
|
+
try {
|
|
405
|
+
return fs.readdirSync(directory);
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
if (error.code === "ENOENT")
|
|
409
|
+
return [];
|
|
410
|
+
throw error;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/** An empty id would name the whole `threads` directory. */
|
|
414
|
+
function requireId(workId) {
|
|
415
|
+
if (!workId)
|
|
416
|
+
throw new Error("a work id is required, and an empty one would name every thread");
|
|
417
|
+
}
|
|
418
|
+
/** Renews a claim or a last use; a file gone meanwhile has nothing to keep. */
|
|
419
|
+
function touch(file) {
|
|
420
|
+
const now = new Date();
|
|
421
|
+
try {
|
|
422
|
+
fs.utimesSync(file, now, now);
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
if (error.code !== "ENOENT")
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function pidOf(owner) {
|
|
430
|
+
return Number(owner.split(":")[0]);
|
|
431
|
+
}
|
|
432
|
+
function isAlive(pid) {
|
|
433
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
434
|
+
return false;
|
|
435
|
+
try {
|
|
436
|
+
process.kill(pid, 0);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
// EPERM: it exists and belongs to somebody else.
|
|
441
|
+
return error.code === "EPERM";
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
//# sourceMappingURL=ThreadMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadMap.js","sourceRoot":"","sources":["../src/ThreadMap.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAI5C,2DAA2D;AAC3D,eAAO,MAAM,YAAY,EAAE,YAwC1B,CAAC"}
|