@theford/runly 0.0.0-stage → 0.20.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/LICENSE +202 -0
- package/README.md +157 -2
- package/dist/cli/client.d.ts +80 -0
- package/dist/cli/client.js +294 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/daemon-unit.d.ts +58 -0
- package/dist/cli/daemon-unit.js +289 -0
- package/dist/cli/daemon-unit.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +1482 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/install.d.ts +9 -0
- package/dist/cli/install.js +53 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/logs.d.ts +43 -0
- package/dist/cli/logs.js +232 -0
- package/dist/cli/logs.js.map +1 -0
- package/dist/cli/tether.d.ts +3 -0
- package/dist/cli/tether.js +65 -0
- package/dist/cli/tether.js.map +1 -0
- package/dist/cli/watchdog.d.ts +1 -0
- package/dist/cli/watchdog.js +81 -0
- package/dist/cli/watchdog.js.map +1 -0
- package/dist/core/builds.d.ts +20 -0
- package/dist/core/builds.js +93 -0
- package/dist/core/builds.js.map +1 -0
- package/dist/core/caller-env.d.ts +17 -0
- package/dist/core/caller-env.js +77 -0
- package/dist/core/caller-env.js.map +1 -0
- package/dist/core/diagnostics.d.ts +68 -0
- package/dist/core/diagnostics.js +34 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/env-vars.d.ts +35 -0
- package/dist/core/env-vars.js +32 -0
- package/dist/core/env-vars.js.map +1 -0
- package/dist/core/events.d.ts +10 -0
- package/dist/core/events.js +42 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/exec.d.ts +22 -0
- package/dist/core/exec.js +84 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/journal.d.ts +227 -0
- package/dist/core/journal.js +395 -0
- package/dist/core/journal.js.map +1 -0
- package/dist/core/logs.d.ts +56 -0
- package/dist/core/logs.js +259 -0
- package/dist/core/logs.js.map +1 -0
- package/dist/core/manifest.d.ts +292 -0
- package/dist/core/manifest.js +179 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/namespaces.d.ts +7 -0
- package/dist/core/namespaces.js +59 -0
- package/dist/core/namespaces.js.map +1 -0
- package/dist/core/paths.d.ts +31 -0
- package/dist/core/paths.js +65 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/policy.d.ts +94 -0
- package/dist/core/policy.js +122 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/ports.d.ts +52 -0
- package/dist/core/ports.js +94 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/presets.d.ts +25 -0
- package/dist/core/presets.js +86 -0
- package/dist/core/presets.js.map +1 -0
- package/dist/core/procscan.d.ts +111 -0
- package/dist/core/procscan.js +342 -0
- package/dist/core/procscan.js.map +1 -0
- package/dist/core/retention.d.ts +97 -0
- package/dist/core/retention.js +322 -0
- package/dist/core/retention.js.map +1 -0
- package/dist/core/sleep.d.ts +51 -0
- package/dist/core/sleep.js +99 -0
- package/dist/core/sleep.js.map +1 -0
- package/dist/core/tree-ledger.d.ts +39 -0
- package/dist/core/tree-ledger.js +92 -0
- package/dist/core/tree-ledger.js.map +1 -0
- package/dist/core/types.d.ts +21 -0
- package/dist/core/types.js +6 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/units.d.ts +20 -0
- package/dist/core/units.js +69 -0
- package/dist/core/units.js.map +1 -0
- package/dist/core/upkeep.d.ts +90 -0
- package/dist/core/upkeep.js +176 -0
- package/dist/core/upkeep.js.map +1 -0
- package/dist/core/util.d.ts +46 -0
- package/dist/core/util.js +168 -0
- package/dist/core/util.js.map +1 -0
- package/dist/core/version.d.ts +39 -0
- package/dist/core/version.js +144 -0
- package/dist/core/version.js.map +1 -0
- package/dist/core/worktree.d.ts +51 -0
- package/dist/core/worktree.js +309 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/daemon/budget.d.ts +155 -0
- package/dist/daemon/budget.js +288 -0
- package/dist/daemon/budget.js.map +1 -0
- package/dist/daemon/election.d.ts +9 -0
- package/dist/daemon/election.js +140 -0
- package/dist/daemon/election.js.map +1 -0
- package/dist/daemon/engine.d.ts +1703 -0
- package/dist/daemon/engine.js +5305 -0
- package/dist/daemon/engine.js.map +1 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +412 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/proxy.d.ts +108 -0
- package/dist/daemon/proxy.js +615 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +101 -0
- package/dist/daemon/supervisor.js +493 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/drivers/appliances.d.ts +11 -0
- package/dist/drivers/appliances.js +174 -0
- package/dist/drivers/appliances.js.map +1 -0
- package/dist/drivers/datastores.d.ts +144 -0
- package/dist/drivers/datastores.js +775 -0
- package/dist/drivers/datastores.js.map +1 -0
- package/dist/drivers/preview.d.ts +69 -0
- package/dist/drivers/preview.js +605 -0
- package/dist/drivers/preview.js.map +1 -0
- package/dist/drivers/types.d.ts +70 -0
- package/dist/drivers/types.js +13 -0
- package/dist/drivers/types.js.map +1 -0
- package/package.json +63 -4
- package/schema/backlot.schema.json +549 -0
- package/schema/runly.schema.json +556 -0
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon's L4 proxy (decision 0033).
|
|
3
|
+
*
|
|
4
|
+
* Every service port of an environment has two numbers: the PUBLIC port, which
|
|
5
|
+
* this module listens on (127.0.0.1 and ::1) for the environment's whole life,
|
|
6
|
+
* and an INTERNAL port the service is started on, fresh at every start. Bytes
|
|
7
|
+
* are piped between the two without looking at them — no HTTP awareness, so
|
|
8
|
+
* WebSockets, gRPC, a database wire protocol all pass the same way.
|
|
9
|
+
*
|
|
10
|
+
* What the indirection buys:
|
|
11
|
+
* - the public port survives every restart (an `up` that rebuilt, reset-data,
|
|
12
|
+
* a quiesce and the next bind), so a URL handed out once stays good;
|
|
13
|
+
* - a connection that arrives while its service is (re)starting is HELD,
|
|
14
|
+
* bounded, and forwarded once the service is ready, instead of being refused;
|
|
15
|
+
* - client→server bytes and the time of the last of them are counted per
|
|
16
|
+
* environment and port — the activity signal idle detection reads (step 6 of
|
|
17
|
+
* the lifecycle work). runly's own readiness probes go to the internal port,
|
|
18
|
+
* so they never count.
|
|
19
|
+
*
|
|
20
|
+
* It holds no policy. The engine says when a target is starting, up (on which
|
|
21
|
+
* internal port) or down; the wake hook (decision 0035) lets the engine start
|
|
22
|
+
* a stopped service on the first connection, which is held meanwhile.
|
|
23
|
+
*/
|
|
24
|
+
import { createServer, connect } from 'node:net';
|
|
25
|
+
import { logEvent } from '../core/events.js';
|
|
26
|
+
/** How long a connection may wait for its service to become ready. */
|
|
27
|
+
export const HOLD_MS = () => Number(process.env.BACKLOT_PROXY_HOLD_MS ?? 90_000);
|
|
28
|
+
/** Per-target bound on held connections, so a client retry storm cannot exhaust fds. */
|
|
29
|
+
const MAX_HELD = 512;
|
|
30
|
+
/** Client bytes kept for a replay; a request larger than this is not retried. */
|
|
31
|
+
const MAX_REPLAY_BYTES = 1024 * 1024;
|
|
32
|
+
/**
|
|
33
|
+
* Every connection's carried bytes together, across the daemon (0.19): 1 MB
|
|
34
|
+
* each times a few hundred held uploads was unbounded memory. Past this, a
|
|
35
|
+
* connection that would carry more is no longer retryable and keeps nothing.
|
|
36
|
+
*/
|
|
37
|
+
const replayCapBytes = () => {
|
|
38
|
+
const v = Number(process.env.BACKLOT_PROXY_REPLAY_CAP_BYTES);
|
|
39
|
+
return Number.isFinite(v) && v >= 0 ? v : 64 * 1024 * 1024;
|
|
40
|
+
};
|
|
41
|
+
let carriedTotal = 0;
|
|
42
|
+
/** What every connection carries for a replay right now (tests, `status`). */
|
|
43
|
+
export const replayCarriedBytes = () => carriedTotal;
|
|
44
|
+
/** Give back what `carry` holds; idempotent. */
|
|
45
|
+
function dropCarry(carry) {
|
|
46
|
+
carriedTotal = Math.max(0, carriedTotal - carry.bytes);
|
|
47
|
+
carry.bytes = 0;
|
|
48
|
+
carry.chunks = [];
|
|
49
|
+
}
|
|
50
|
+
/** Resets tolerated while the target is still `up` (the supervisor has not seen the exit yet). */
|
|
51
|
+
const MAX_UP_RESETS = 5;
|
|
52
|
+
/** Relaunches one connection's delivered bytes may be carried to. */
|
|
53
|
+
const MAX_REPLAYS = 1;
|
|
54
|
+
/** HTTP methods that are safe to repeat (RFC 9110 §9.2.1/§9.2.2) — no side effect a second run could double. */
|
|
55
|
+
const IDEMPOTENT = /^(GET|HEAD|OPTIONS) /;
|
|
56
|
+
/**
|
|
57
|
+
* May bytes a process already received be sent to the next one? Only when the
|
|
58
|
+
* connection's first bytes are an HTTP request with a method that is safe to
|
|
59
|
+
* repeat: the dead process may have acted on what it read (charged a card,
|
|
60
|
+
* inserted a row) before it died, and a replay would act a second time. Any
|
|
61
|
+
* other request — POST, PUT, PATCH, DELETE, a database or TLS wire protocol,
|
|
62
|
+
* a first chunk too short to tell — is not replayed once delivered.
|
|
63
|
+
*/
|
|
64
|
+
export function replayable(chunks) {
|
|
65
|
+
const head = Buffer.concat(chunks.length > 1 ? chunks.slice(0, 4) : chunks).subarray(0, 8).toString('latin1');
|
|
66
|
+
return IDEMPOTENT.test(head);
|
|
67
|
+
}
|
|
68
|
+
class Target {
|
|
69
|
+
envId;
|
|
70
|
+
key;
|
|
71
|
+
port;
|
|
72
|
+
hub;
|
|
73
|
+
servers = [];
|
|
74
|
+
state = 'down';
|
|
75
|
+
internalPort;
|
|
76
|
+
service;
|
|
77
|
+
clientBytes = 0;
|
|
78
|
+
lastActivityAt = null;
|
|
79
|
+
accepted = 0;
|
|
80
|
+
open = new Set();
|
|
81
|
+
waiters = [];
|
|
82
|
+
constructor(envId, key, port, hub) {
|
|
83
|
+
this.envId = envId;
|
|
84
|
+
this.key = key;
|
|
85
|
+
this.port = port;
|
|
86
|
+
this.hub = hub;
|
|
87
|
+
}
|
|
88
|
+
stats() {
|
|
89
|
+
return {
|
|
90
|
+
port: this.port,
|
|
91
|
+
service: this.service,
|
|
92
|
+
state: this.state,
|
|
93
|
+
internalPort: this.state === 'up' ? this.internalPort : undefined,
|
|
94
|
+
clientBytes: this.clientBytes,
|
|
95
|
+
lastActivityAt: this.lastActivityAt,
|
|
96
|
+
open: this.open.size,
|
|
97
|
+
held: this.waiters.length,
|
|
98
|
+
accepted: this.accepted,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
onConnection(client) {
|
|
102
|
+
this.accepted++;
|
|
103
|
+
// Never let a peer reset crash the daemon.
|
|
104
|
+
client.on('error', () => client.destroy());
|
|
105
|
+
if (this.state === 'up' && this.internalPort !== undefined) {
|
|
106
|
+
this.forward(client, this.internalPort);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (this.state === 'down' && !this.hub.wake(this.envId, this.key)) {
|
|
110
|
+
client.destroy();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.hold(client);
|
|
114
|
+
}
|
|
115
|
+
hold(client, carry) {
|
|
116
|
+
if (this.waiters.length >= MAX_HELD) {
|
|
117
|
+
client.destroy();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// A paused socket buffers what the client sends (and TCP backpressure
|
|
121
|
+
// stops it beyond that), so nothing is lost while it waits.
|
|
122
|
+
client.pause();
|
|
123
|
+
const waiter = {
|
|
124
|
+
socket: client,
|
|
125
|
+
carry,
|
|
126
|
+
timer: setTimeout(() => {
|
|
127
|
+
this.dropWaiter(waiter);
|
|
128
|
+
client.destroy();
|
|
129
|
+
}, carry ? Math.max(0, carry.deadline - Date.now()) : HOLD_MS()),
|
|
130
|
+
};
|
|
131
|
+
waiter.timer.unref();
|
|
132
|
+
client.once('close', () => this.dropWaiter(waiter));
|
|
133
|
+
this.waiters.push(waiter);
|
|
134
|
+
}
|
|
135
|
+
dropWaiter(waiter) {
|
|
136
|
+
clearTimeout(waiter.timer);
|
|
137
|
+
const i = this.waiters.indexOf(waiter);
|
|
138
|
+
if (i >= 0)
|
|
139
|
+
this.waiters.splice(i, 1);
|
|
140
|
+
}
|
|
141
|
+
/** Release every held connection: forward them, or close them when the target is not up. */
|
|
142
|
+
flush() {
|
|
143
|
+
const waiters = this.waiters;
|
|
144
|
+
this.waiters = [];
|
|
145
|
+
for (const w of waiters) {
|
|
146
|
+
clearTimeout(w.timer);
|
|
147
|
+
if (w.socket.destroyed)
|
|
148
|
+
continue;
|
|
149
|
+
if (this.state === 'up' && this.internalPort !== undefined)
|
|
150
|
+
this.forward(w.socket, this.internalPort, w.carry);
|
|
151
|
+
else
|
|
152
|
+
w.socket.destroy();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Pipe `client` to the service on `internalPort`.
|
|
157
|
+
*
|
|
158
|
+
* Until the service sends its first byte back, the client's bytes are also
|
|
159
|
+
* kept (`carry`). A service that dies in the window before the supervisor
|
|
160
|
+
* notices — the kernel accepted the connection, then the process exited and
|
|
161
|
+
* the socket was reset or closed with nothing written — looks to the client
|
|
162
|
+
* like a refused connect, and is retried and held the same way (decision
|
|
163
|
+
* 0035) when that is safe:
|
|
164
|
+
* - nothing of the client's reached the process (refused, or lost before
|
|
165
|
+
* the proxy wrote a byte upstream): always — it cannot have acted;
|
|
166
|
+
* - bytes reached it: only for an idempotent HTTP request (`replayable`),
|
|
167
|
+
* and only to ONE more process (`MAX_REPLAYS`).
|
|
168
|
+
* Otherwise the client sees the close or reset, as it would without a proxy
|
|
169
|
+
* (decision 0039, corrected in 0.18.1).
|
|
170
|
+
*/
|
|
171
|
+
forward(client, internalPort, carry) {
|
|
172
|
+
if (!this.open.has(client)) {
|
|
173
|
+
this.open.add(client);
|
|
174
|
+
client.once('close', () => this.open.delete(client));
|
|
175
|
+
}
|
|
176
|
+
const replay = carry ?? { chunks: [], bytes: 0, ended: false, resets: 0, replays: 0, deadline: Date.now() + HOLD_MS() };
|
|
177
|
+
if (!carry)
|
|
178
|
+
client.once('close', () => dropCarry(replay));
|
|
179
|
+
connectInternal(internalPort, (err, upstream) => {
|
|
180
|
+
if (err || !upstream) {
|
|
181
|
+
this.refused(client, replay);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (client.destroyed) {
|
|
185
|
+
upstream.destroy();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
let answered = false;
|
|
189
|
+
let retryable = replay.bytes <= MAX_REPLAY_BYTES && !replay.capped;
|
|
190
|
+
let settled = false;
|
|
191
|
+
// Did any client byte reach this process? Before one did, it cannot have
|
|
192
|
+
// acted on the request, so a retry is not a replay.
|
|
193
|
+
let delivered = replay.chunks.length > 0;
|
|
194
|
+
// May this connection be retried if the process goes away unanswered?
|
|
195
|
+
const canRetry = () => !answered && retryable && (!delivered || (replay.replays < MAX_REPLAYS && replayable(replay.chunks)));
|
|
196
|
+
// Bytes the client sent while it waited (or before a reset) go first.
|
|
197
|
+
for (const chunk of replay.chunks)
|
|
198
|
+
upstream.write(chunk);
|
|
199
|
+
if (replay.ended)
|
|
200
|
+
upstream.end();
|
|
201
|
+
const onData = (chunk) => {
|
|
202
|
+
// Count before forwarding.
|
|
203
|
+
this.clientBytes += chunk.length;
|
|
204
|
+
this.lastActivityAt = Date.now();
|
|
205
|
+
this.hub.noteActivity(this.envId, this.key);
|
|
206
|
+
if (!answered && retryable) {
|
|
207
|
+
if (replay.bytes + chunk.length > MAX_REPLAY_BYTES || carriedTotal + chunk.length > replayCapBytes()) {
|
|
208
|
+
retryable = false;
|
|
209
|
+
replay.capped = true;
|
|
210
|
+
dropCarry(replay);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
replay.chunks.push(chunk);
|
|
214
|
+
replay.bytes += chunk.length;
|
|
215
|
+
carriedTotal += chunk.length;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
delivered = true;
|
|
219
|
+
if (!upstream.write(chunk))
|
|
220
|
+
client.pause();
|
|
221
|
+
};
|
|
222
|
+
const onDrain = () => client.resume();
|
|
223
|
+
const onEnd = () => {
|
|
224
|
+
replay.ended = true;
|
|
225
|
+
upstream.end();
|
|
226
|
+
};
|
|
227
|
+
const onClientClose = () => upstream.destroy();
|
|
228
|
+
const detach = () => {
|
|
229
|
+
client.off('data', onData);
|
|
230
|
+
client.off('end', onEnd);
|
|
231
|
+
client.off('close', onClientClose);
|
|
232
|
+
upstream.off('drain', onDrain);
|
|
233
|
+
upstream.unpipe(client);
|
|
234
|
+
};
|
|
235
|
+
// The service went away before it said anything, and retrying is safe
|
|
236
|
+
// (canRetry): retry like a refusal.
|
|
237
|
+
const lost = () => {
|
|
238
|
+
if (settled)
|
|
239
|
+
return;
|
|
240
|
+
settled = true;
|
|
241
|
+
if (delivered)
|
|
242
|
+
replay.replays++;
|
|
243
|
+
detach();
|
|
244
|
+
upstream.destroy();
|
|
245
|
+
if (client.destroyed)
|
|
246
|
+
return;
|
|
247
|
+
client.pause();
|
|
248
|
+
this.refused(client, replay, true);
|
|
249
|
+
};
|
|
250
|
+
upstream.once('data', () => {
|
|
251
|
+
answered = true;
|
|
252
|
+
dropCarry(replay);
|
|
253
|
+
});
|
|
254
|
+
upstream.on('error', () => {
|
|
255
|
+
if (canRetry())
|
|
256
|
+
lost();
|
|
257
|
+
else
|
|
258
|
+
client.destroy();
|
|
259
|
+
});
|
|
260
|
+
upstream.on('drain', onDrain);
|
|
261
|
+
client.on('data', onData);
|
|
262
|
+
client.on('end', onEnd);
|
|
263
|
+
client.on('close', onClientClose);
|
|
264
|
+
upstream.pipe(client, { end: false });
|
|
265
|
+
// Half-closes travel on (the service's FIN ends the client's side), and
|
|
266
|
+
// a full close of either side ends the pair — unless the service closed
|
|
267
|
+
// before it said anything and retrying is safe: a lost connection, retried above.
|
|
268
|
+
const finish = (closed) => {
|
|
269
|
+
if (canRetry() && !client.destroyed) {
|
|
270
|
+
lost();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (settled)
|
|
274
|
+
return;
|
|
275
|
+
if (!client.destroyed)
|
|
276
|
+
client.end();
|
|
277
|
+
if (!closed)
|
|
278
|
+
return;
|
|
279
|
+
settled = true;
|
|
280
|
+
setTimeout(() => client.destroy(), 10_000).unref();
|
|
281
|
+
};
|
|
282
|
+
upstream.once('end', () => finish(false));
|
|
283
|
+
upstream.once('close', () => finish(true));
|
|
284
|
+
client.resume();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The service did not accept, or accepted and went away before answering:
|
|
289
|
+
* it may have just crashed, with the supervisor about to relaunch it (the
|
|
290
|
+
* self-restart gap, decision 0035). The connection is held — retried while
|
|
291
|
+
* the target still says `up`, held while it is `starting`, woken when it
|
|
292
|
+
* went `down` — until the hold deadline; only then is it closed. A service
|
|
293
|
+
* that keeps closing connections unanswered while it is `up` is believed
|
|
294
|
+
* after a few tries: that is its answer, not a crash.
|
|
295
|
+
*/
|
|
296
|
+
refused(client, carry, reset = false) {
|
|
297
|
+
if (client.destroyed)
|
|
298
|
+
return;
|
|
299
|
+
if (Date.now() >= carry.deadline) {
|
|
300
|
+
client.destroy();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (this.state === 'starting') {
|
|
304
|
+
this.hold(client, carry);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (this.state === 'down') {
|
|
308
|
+
if (this.hub.wake(this.envId, this.key))
|
|
309
|
+
this.hold(client, carry);
|
|
310
|
+
else
|
|
311
|
+
client.destroy();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (reset && ++carry.resets > MAX_UP_RESETS) {
|
|
315
|
+
// Up all along and still closing on us: pass its close on.
|
|
316
|
+
client.end();
|
|
317
|
+
setTimeout(() => client.destroy(), 10_000).unref();
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
setTimeout(() => {
|
|
321
|
+
if (client.destroyed)
|
|
322
|
+
return;
|
|
323
|
+
if (this.state === 'up' && this.internalPort !== undefined)
|
|
324
|
+
this.forward(client, this.internalPort, carry);
|
|
325
|
+
else
|
|
326
|
+
this.refused(client, carry);
|
|
327
|
+
}, 200).unref();
|
|
328
|
+
}
|
|
329
|
+
close() {
|
|
330
|
+
for (const s of this.servers)
|
|
331
|
+
s.close();
|
|
332
|
+
this.servers = [];
|
|
333
|
+
this.state = 'down';
|
|
334
|
+
this.flush();
|
|
335
|
+
for (const s of this.open)
|
|
336
|
+
s.destroy();
|
|
337
|
+
this.open.clear();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Connect to a service's internal port. A service told to listen on
|
|
342
|
+
* `localhost` may have bound IPv4, IPv6, or both, so try each loopback.
|
|
343
|
+
*/
|
|
344
|
+
function connectInternal(port, done) {
|
|
345
|
+
const hosts = ['127.0.0.1', '::1'];
|
|
346
|
+
const attempt = (i, lastErr) => {
|
|
347
|
+
if (i >= hosts.length)
|
|
348
|
+
return done(lastErr ?? new Error('no loopback answered'));
|
|
349
|
+
const sock = connect({ port, host: hosts[i], allowHalfOpen: true });
|
|
350
|
+
const onError = (err) => {
|
|
351
|
+
sock.destroy();
|
|
352
|
+
attempt(i + 1, err);
|
|
353
|
+
};
|
|
354
|
+
sock.once('error', onError);
|
|
355
|
+
sock.once('connect', () => {
|
|
356
|
+
sock.off('error', onError);
|
|
357
|
+
done(null, sock);
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
attempt(0, null);
|
|
361
|
+
}
|
|
362
|
+
export class PortInUse extends Error {
|
|
363
|
+
port;
|
|
364
|
+
host;
|
|
365
|
+
constructor(port, host) {
|
|
366
|
+
super(`port ${port} is already in use on ${host}`);
|
|
367
|
+
this.port = port;
|
|
368
|
+
this.host = host;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/** Bind one listener; resolves false when the address family is absent (no IPv6). */
|
|
372
|
+
function listenOn(server, port, host) {
|
|
373
|
+
return new Promise((resolve, reject) => {
|
|
374
|
+
const onError = (err) => {
|
|
375
|
+
server.off('listening', onListening);
|
|
376
|
+
if (err.code === 'EADDRINUSE' || err.code === 'EACCES')
|
|
377
|
+
reject(new PortInUse(port, host));
|
|
378
|
+
else if (err.code === 'EADDRNOTAVAIL' || err.code === 'EAFNOSUPPORT')
|
|
379
|
+
resolve(false);
|
|
380
|
+
else
|
|
381
|
+
reject(err);
|
|
382
|
+
};
|
|
383
|
+
const onListening = () => {
|
|
384
|
+
server.off('error', onError);
|
|
385
|
+
resolve(true);
|
|
386
|
+
};
|
|
387
|
+
server.once('error', onError);
|
|
388
|
+
server.once('listening', onListening);
|
|
389
|
+
// exclusive: a second daemon (another state root) must collide, not share.
|
|
390
|
+
server.listen({ port, host, exclusive: true });
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
export class ProxyHub {
|
|
394
|
+
targets = new Map();
|
|
395
|
+
/**
|
|
396
|
+
* Internal ports handed to a start that is not `up` yet, by env/key. A port
|
|
397
|
+
* is probed free when it is allocated, and the service binds it seconds
|
|
398
|
+
* later; without this, two starts in that window were given the same port
|
|
399
|
+
* and one environment's public URL served the other's process.
|
|
400
|
+
*/
|
|
401
|
+
reservedInternal = new Map();
|
|
402
|
+
wakeHook;
|
|
403
|
+
activityHook;
|
|
404
|
+
id(envId, key) {
|
|
405
|
+
return `${envId}\u0000${key}`;
|
|
406
|
+
}
|
|
407
|
+
/** The engine installs this (decision 0035): start a stopped service on its first connection. */
|
|
408
|
+
setWakeHook(hook) {
|
|
409
|
+
this.wakeHook = hook;
|
|
410
|
+
}
|
|
411
|
+
/** Optional observer of client bytes (idle bookkeeping lives with the caller). */
|
|
412
|
+
setActivityHook(hook) {
|
|
413
|
+
this.activityHook = hook;
|
|
414
|
+
}
|
|
415
|
+
wake(envId, key) {
|
|
416
|
+
try {
|
|
417
|
+
return this.wakeHook?.(envId, key) ?? false;
|
|
418
|
+
}
|
|
419
|
+
catch {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
noteActivity(envId, key) {
|
|
424
|
+
this.activityHook?.(envId, key);
|
|
425
|
+
}
|
|
426
|
+
/** Where the service behind env/key listens, also while it restarts (decision 0035). */
|
|
427
|
+
internalPortOf(envId, key) {
|
|
428
|
+
return this.targets.get(this.id(envId, key))?.internalPort;
|
|
429
|
+
}
|
|
430
|
+
/** Start a target's activity clock from the journal, so a daemon restart keeps it (decision 0035). */
|
|
431
|
+
seedActivity(envId, key, at) {
|
|
432
|
+
const t = this.targets.get(this.id(envId, key));
|
|
433
|
+
if (t && (t.lastActivityAt === null || t.lastActivityAt < at))
|
|
434
|
+
t.lastActivityAt = at;
|
|
435
|
+
}
|
|
436
|
+
/** The last client byte per port key of an environment (null = none yet). */
|
|
437
|
+
activity(envId) {
|
|
438
|
+
const out = {};
|
|
439
|
+
for (const t of this.targets.values())
|
|
440
|
+
if (t.envId === envId)
|
|
441
|
+
out[t.key] = t.lastActivityAt;
|
|
442
|
+
return out;
|
|
443
|
+
}
|
|
444
|
+
/** Every env id with a listener (doctor's stale-listener check, decision 0037). */
|
|
445
|
+
envIds() {
|
|
446
|
+
return new Set([...this.targets.values()].map((t) => t.envId));
|
|
447
|
+
}
|
|
448
|
+
/** Is the public listener for this env/key currently held, on this port? */
|
|
449
|
+
holds(envId, key, port) {
|
|
450
|
+
const t = this.targets.get(this.id(envId, key));
|
|
451
|
+
return t !== undefined && t.port === port && t.servers.length > 0;
|
|
452
|
+
}
|
|
453
|
+
/** Every public port this daemon is listening on. */
|
|
454
|
+
heldPorts() {
|
|
455
|
+
const out = new Set();
|
|
456
|
+
for (const t of this.targets.values())
|
|
457
|
+
if (t.servers.length > 0)
|
|
458
|
+
out.add(t.port);
|
|
459
|
+
return out;
|
|
460
|
+
}
|
|
461
|
+
/** Every internal port currently assigned to a target (up or not) or reserved for a start, so none is handed out twice. */
|
|
462
|
+
assignedInternalPorts() {
|
|
463
|
+
const out = new Set(this.reservedInternal.values());
|
|
464
|
+
for (const t of this.targets.values())
|
|
465
|
+
if (t.internalPort !== undefined)
|
|
466
|
+
out.add(t.internalPort);
|
|
467
|
+
return out;
|
|
468
|
+
}
|
|
469
|
+
/** Hold `port` for the start of env/key until it is `up` (then the target owns it) or goes down. */
|
|
470
|
+
reserveInternal(envId, key, port) {
|
|
471
|
+
this.reservedInternal.set(this.id(envId, key), port);
|
|
472
|
+
}
|
|
473
|
+
release(id) {
|
|
474
|
+
this.reservedInternal.delete(id);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Listen on `port` for env/key (idempotent). Throws PortInUse when another
|
|
478
|
+
* process holds it; any previous listener for this env/key on a different
|
|
479
|
+
* port is closed first, and its counters carried over.
|
|
480
|
+
*/
|
|
481
|
+
async listen(envId, key, port) {
|
|
482
|
+
const id = this.id(envId, key);
|
|
483
|
+
const existing = this.targets.get(id);
|
|
484
|
+
if (existing && existing.port === port && existing.servers.length > 0)
|
|
485
|
+
return;
|
|
486
|
+
const target = new Target(envId, key, port, this);
|
|
487
|
+
if (existing) {
|
|
488
|
+
target.clientBytes = existing.clientBytes;
|
|
489
|
+
target.lastActivityAt = existing.lastActivityAt;
|
|
490
|
+
target.accepted = existing.accepted;
|
|
491
|
+
target.state = existing.state;
|
|
492
|
+
target.internalPort = existing.internalPort;
|
|
493
|
+
target.service = existing.service;
|
|
494
|
+
}
|
|
495
|
+
const servers = [];
|
|
496
|
+
try {
|
|
497
|
+
for (const host of ['127.0.0.1', '::1']) {
|
|
498
|
+
const server = createServer({ allowHalfOpen: true, pauseOnConnect: true }, (sock) => target.onConnection(sock));
|
|
499
|
+
if (await listenOn(server, port, host)) {
|
|
500
|
+
server.on('error', (err) => logEvent({ level: 'warn', kind: 'proxy', envId, detail: `listener ${host}:${port} failed: ${err.message}` }));
|
|
501
|
+
servers.push(server);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (servers.length === 0)
|
|
505
|
+
throw new PortInUse(port, 'loopback');
|
|
506
|
+
}
|
|
507
|
+
catch (err) {
|
|
508
|
+
for (const s of servers)
|
|
509
|
+
s.close();
|
|
510
|
+
throw err;
|
|
511
|
+
}
|
|
512
|
+
if (existing) {
|
|
513
|
+
// Move held connections too: they are waiting for the SERVICE, not the port.
|
|
514
|
+
target.waiters = existing.waiters;
|
|
515
|
+
existing.waiters = [];
|
|
516
|
+
existing.close();
|
|
517
|
+
}
|
|
518
|
+
target.servers = servers;
|
|
519
|
+
this.targets.set(id, target);
|
|
520
|
+
}
|
|
521
|
+
/** New connections are held until `up` (or dropped by `down`). */
|
|
522
|
+
starting(envId, key, service) {
|
|
523
|
+
const t = this.targets.get(this.id(envId, key));
|
|
524
|
+
if (!t)
|
|
525
|
+
return;
|
|
526
|
+
t.state = 'starting';
|
|
527
|
+
if (service)
|
|
528
|
+
t.service = service;
|
|
529
|
+
}
|
|
530
|
+
/** The service behind env/key is ready on `internalPort`; held connections go through. */
|
|
531
|
+
up(envId, key, internalPort, service) {
|
|
532
|
+
const t = this.targets.get(this.id(envId, key));
|
|
533
|
+
if (!t)
|
|
534
|
+
return;
|
|
535
|
+
t.state = 'up';
|
|
536
|
+
t.internalPort = internalPort;
|
|
537
|
+
this.reservedInternal.set(this.id(envId, key), internalPort);
|
|
538
|
+
if (service)
|
|
539
|
+
t.service = service;
|
|
540
|
+
t.flush();
|
|
541
|
+
}
|
|
542
|
+
/** Nothing is (or will soon be) behind env/key: held connections are closed. */
|
|
543
|
+
down(envId, key) {
|
|
544
|
+
this.release(this.id(envId, key));
|
|
545
|
+
const t = this.targets.get(this.id(envId, key));
|
|
546
|
+
if (!t)
|
|
547
|
+
return;
|
|
548
|
+
t.state = 'down';
|
|
549
|
+
t.internalPort = undefined;
|
|
550
|
+
t.flush();
|
|
551
|
+
}
|
|
552
|
+
/** A service was stopped: its targets go down unless a restart already marked them starting. */
|
|
553
|
+
serviceStopped(envId, service) {
|
|
554
|
+
for (const t of this.targets.values()) {
|
|
555
|
+
if (t.envId === envId && t.service === service && t.state === 'up') {
|
|
556
|
+
t.state = 'down';
|
|
557
|
+
t.internalPort = undefined;
|
|
558
|
+
this.release(this.id(t.envId, t.key));
|
|
559
|
+
t.flush();
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/** Every `starting` target of an env that never reached `up` goes down (a failed bind). */
|
|
564
|
+
settle(envId) {
|
|
565
|
+
for (const t of this.targets.values()) {
|
|
566
|
+
if (t.envId === envId && t.state === 'starting') {
|
|
567
|
+
t.state = 'down';
|
|
568
|
+
t.internalPort = undefined;
|
|
569
|
+
this.release(this.id(t.envId, t.key));
|
|
570
|
+
t.flush();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
state(envId, key) {
|
|
575
|
+
return this.targets.get(this.id(envId, key))?.state;
|
|
576
|
+
}
|
|
577
|
+
/** Close one env/key listener (a port key the manifest dropped). */
|
|
578
|
+
closeKey(envId, key) {
|
|
579
|
+
const id = this.id(envId, key);
|
|
580
|
+
this.targets.get(id)?.close();
|
|
581
|
+
this.targets.delete(id);
|
|
582
|
+
this.release(id);
|
|
583
|
+
}
|
|
584
|
+
/** The port keys this daemon holds a listener for, for one environment. */
|
|
585
|
+
keysOf(envId) {
|
|
586
|
+
return [...this.targets.values()].filter((t) => t.envId === envId).map((t) => t.key);
|
|
587
|
+
}
|
|
588
|
+
/** Release every listener of an environment (teardown). */
|
|
589
|
+
closeEnv(envId) {
|
|
590
|
+
for (const [id, t] of this.targets) {
|
|
591
|
+
if (t.envId === envId) {
|
|
592
|
+
t.close();
|
|
593
|
+
this.targets.delete(id);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
for (const id of [...this.reservedInternal.keys()])
|
|
597
|
+
if (id.startsWith(`${envId}\u0000`))
|
|
598
|
+
this.reservedInternal.delete(id);
|
|
599
|
+
}
|
|
600
|
+
closeAll() {
|
|
601
|
+
for (const t of this.targets.values())
|
|
602
|
+
t.close();
|
|
603
|
+
this.targets.clear();
|
|
604
|
+
this.reservedInternal.clear();
|
|
605
|
+
}
|
|
606
|
+
/** Stats by port key for one environment. */
|
|
607
|
+
stats(envId) {
|
|
608
|
+
const out = {};
|
|
609
|
+
for (const t of this.targets.values())
|
|
610
|
+
if (t.envId === envId)
|
|
611
|
+
out[t.key] = t.stats();
|
|
612
|
+
return out;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/daemon/proxy.ts"],"names":[],"mappings":"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"}
|