sliftutils 1.7.19 → 1.7.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +15 -2
- package/package.json +2 -2
- package/storage/remoteStorage/ArchivesRemote.d.ts +3 -1
- package/storage/remoteStorage/ArchivesRemote.ts +2 -2
- package/storage/remoteStorage/createArchives.d.ts +1 -0
- package/storage/remoteStorage/createArchives.ts +38 -7
- package/storage/remoteStorage/deployTakeover.d.ts +4 -0
- package/storage/remoteStorage/deployTakeover.ts +9 -0
- package/storage/remoteStorage/dist/blobStore.ts.cache +16 -4
- package/storage/remoteStorage/dist/createArchives.ts.cache +14 -3
- package/storage/remoteStorage/dist/deployTakeover.ts.cache +73 -39
- package/storage/remoteStorage/dist/storageServerState.ts.cache +22 -9
- package/storage/remoteStorage/sourceWrapper.d.ts +4 -0
- package/storage/remoteStorage/sourceWrapper.ts +11 -1
- package/storage/remoteStorage/storageController.d.ts +3 -1
- package/storage/remoteStorage/storageController.ts +7 -2
- package/yarn.lock +4 -4
package/index.d.ts
CHANGED
|
@@ -2871,7 +2871,9 @@ declare module "sliftutils/storage/remoteStorage/ArchivesRemote" {
|
|
|
2871
2871
|
private lastDeniedLog;
|
|
2872
2872
|
getDebugName(): string;
|
|
2873
2873
|
isConnected(): boolean;
|
|
2874
|
-
ping(): Promise<
|
|
2874
|
+
ping(): Promise<{
|
|
2875
|
+
takeover?: string;
|
|
2876
|
+
}>;
|
|
2875
2877
|
private authenticate;
|
|
2876
2878
|
private callAuthed;
|
|
2877
2879
|
waitingForAccess(): Promise<{
|
|
@@ -3185,6 +3187,7 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
|
|
|
3185
3187
|
getDebugName(): string;
|
|
3186
3188
|
private getState;
|
|
3187
3189
|
private init;
|
|
3190
|
+
private createChainSource;
|
|
3188
3191
|
private buildSources;
|
|
3189
3192
|
private startConfigPoll;
|
|
3190
3193
|
private configRefreshInFlight;
|
|
@@ -3295,6 +3298,10 @@ declare module "sliftutils/storage/remoteStorage/deployTakeover" {
|
|
|
3295
3298
|
* of the deploy overlap points at the alternate port. Pure, in-memory only - the stored routing
|
|
3296
3299
|
* config is never modified, and this must never be applied to data that gets persisted. */
|
|
3297
3300
|
export declare function applyDeployRemap(routing: RemoteConfig): RemoteConfig;
|
|
3301
|
+
/** A stamp of the current remap interpretation, advertised in ping responses - so every connected
|
|
3302
|
+
* client learns of a takeover within one ping interval, instead of waiting for its config poll
|
|
3303
|
+
* or a write rejection. */
|
|
3304
|
+
export declare function getTakeoverStamp(): string | undefined;
|
|
3298
3305
|
/** For the dying process: fast-write flush delays must never extend past this time, and after it
|
|
3299
3306
|
* fast writes flush immediately - so nothing is left in memory when the write window transfers. */
|
|
3300
3307
|
export declare function getFlushDeadline(): number | undefined;
|
|
@@ -3375,6 +3382,10 @@ declare module "sliftutils/storage/remoteStorage/sourceWrapper" {
|
|
|
3375
3382
|
private pings;
|
|
3376
3383
|
private pingTimer;
|
|
3377
3384
|
private loggedConnected;
|
|
3385
|
+
private lastTakeoverStamp;
|
|
3386
|
+
/** Fired when the source's advertised takeover stamp changes (a deploy takeover started or
|
|
3387
|
+
* ended) - the chain refreshes its config, so connected clients learn within one ping. */
|
|
3388
|
+
onServedConfigChanged: (() => void) | undefined;
|
|
3378
3389
|
/** Starts measuring this source's latency (for variable-shard target preference). Only hosted
|
|
3379
3390
|
* remotes are pinged; our own local server counts as 0, everything else as Infinity. */
|
|
3380
3391
|
startPinging(): void;
|
|
@@ -3428,7 +3439,9 @@ declare module "sliftutils/storage/remoteStorage/storageController" {
|
|
|
3428
3439
|
trustedMachines?: TrustRecord[];
|
|
3429
3440
|
};
|
|
3430
3441
|
export declare const RemoteStorageController: import("socket-function/SocketFunctionTypes").SocketRegistered<{
|
|
3431
|
-
ping: () => Promise<
|
|
3442
|
+
ping: () => Promise<{
|
|
3443
|
+
takeover?: string;
|
|
3444
|
+
}>;
|
|
3432
3445
|
authenticate: (token: AuthToken) => Promise<{
|
|
3433
3446
|
machineId: string;
|
|
3434
3447
|
ip: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sliftutils",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.21",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
58
58
|
"preact-old-types": "^10.28.1",
|
|
59
59
|
"shell-quote": "^1.8.3",
|
|
60
|
-
"socket-function": "^1.2.
|
|
60
|
+
"socket-function": "^1.2.26",
|
|
61
61
|
"typenode": "^6.6.1",
|
|
62
62
|
"typesafecss": "*",
|
|
63
63
|
"ws": "^8.18.3",
|
|
@@ -29,7 +29,9 @@ export declare class ArchivesRemote implements IArchives {
|
|
|
29
29
|
private lastDeniedLog;
|
|
30
30
|
getDebugName(): string;
|
|
31
31
|
isConnected(): boolean;
|
|
32
|
-
ping(): Promise<
|
|
32
|
+
ping(): Promise<{
|
|
33
|
+
takeover?: string;
|
|
34
|
+
}>;
|
|
33
35
|
private authenticate;
|
|
34
36
|
private callAuthed;
|
|
35
37
|
waitingForAccess(): Promise<{
|
|
@@ -77,8 +77,8 @@ export class ArchivesRemote implements IArchives {
|
|
|
77
77
|
return SocketFunction.isNodeConnected(this.nodeId);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
public async ping(): Promise<
|
|
81
|
-
await this.controller.ping();
|
|
80
|
+
public async ping(): Promise<{ takeover?: string }> {
|
|
81
|
+
return await this.controller.ping();
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
private async authenticate(): Promise<void> {
|
|
@@ -223,6 +223,29 @@ export class ArchivesChain implements IArchives {
|
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
+
// The server may be MID deploy-takeover: its getConfig returns the in-memory
|
|
227
|
+
// interpretation (window splits pointing at a successor's port), which is never in the
|
|
228
|
+
// routing file. A client connecting during the takeover must start on that
|
|
229
|
+
// interpretation, not discover it minutes later.
|
|
230
|
+
try {
|
|
231
|
+
let probeApi = found.probe.api;
|
|
232
|
+
if (probeApi) {
|
|
233
|
+
let servedConfig = (await probeApi.getConfig()).remoteConfig;
|
|
234
|
+
if (servedConfig) {
|
|
235
|
+
let served = normalizeRemoteConfig(servedConfig);
|
|
236
|
+
if (JSON.stringify(served) !== JSON.stringify(active) && getConfigVersion(served) >= getConfigVersion(active)) {
|
|
237
|
+
console.log(`Adopting the server's in-memory routing interpretation at init for ${this.getDebugName()} (deploy takeover in progress)`);
|
|
238
|
+
active = served;
|
|
239
|
+
for (let source of sources) {
|
|
240
|
+
source.dispose();
|
|
241
|
+
}
|
|
242
|
+
sources = await this.buildSources(active);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch {
|
|
247
|
+
// The raw routing config we already adopted still works
|
|
248
|
+
}
|
|
226
249
|
// The routing fetches double as our first latency measurements: variable-shard picking
|
|
227
250
|
// works immediately, instead of waiting for the first ping pass to land
|
|
228
251
|
for (let source of sources) {
|
|
@@ -241,13 +264,23 @@ export class ArchivesChain implements IArchives {
|
|
|
241
264
|
}
|
|
242
265
|
}
|
|
243
266
|
|
|
267
|
+
private async createChainSource(sourceConfig: HostedConfig | BackblazeConfig): Promise<SourceWrapper> {
|
|
268
|
+
let source = await SourceWrapper.create(sourceConfig);
|
|
269
|
+
// A takeover stamp change in a ping means the server's routing interpretation changed
|
|
270
|
+
// (deploy takeover started/ended); refresh so we learn within one ping interval
|
|
271
|
+
source.onServedConfigChanged = () => {
|
|
272
|
+
console.log(`Storage ${source.getDebugName()} advertised a routing change (deploy takeover); refreshing config for ${this.getDebugName()}`);
|
|
273
|
+
void this.refreshActiveConfig().catch((e: Error) => console.error(`Config refresh failed for ${this.getDebugName()}: ${e.stack ?? e}`));
|
|
274
|
+
};
|
|
275
|
+
// Latency (for variable-shard target preference) is tracked from initialization on
|
|
276
|
+
source.startPinging();
|
|
277
|
+
return source;
|
|
278
|
+
}
|
|
279
|
+
|
|
244
280
|
private async buildSources(config: RemoteConfig): Promise<SourceWrapper[]> {
|
|
245
281
|
let sources: SourceWrapper[] = [];
|
|
246
282
|
for (let sourceConfig of config.sources.map(normalizeSource)) {
|
|
247
|
-
|
|
248
|
-
// Latency (for variable-shard target preference) is tracked from initialization on
|
|
249
|
-
source.startPinging();
|
|
250
|
-
sources.push(source);
|
|
283
|
+
sources.push(await this.createChainSource(sourceConfig));
|
|
251
284
|
}
|
|
252
285
|
return sources;
|
|
253
286
|
}
|
|
@@ -320,9 +353,7 @@ export class ArchivesChain implements IArchives {
|
|
|
320
353
|
oldByConfig.delete(key);
|
|
321
354
|
sources.push(old);
|
|
322
355
|
} else {
|
|
323
|
-
|
|
324
|
-
source.startPinging();
|
|
325
|
-
sources.push(source);
|
|
356
|
+
sources.push(await this.createChainSource(sourceConfig));
|
|
326
357
|
}
|
|
327
358
|
}
|
|
328
359
|
// In-flight requests still hold the old wrappers and finish fine; dispose just stops any
|
|
@@ -16,6 +16,10 @@ export declare function onTakeoverEvent(listener: (event: TakeoverEvent) => void
|
|
|
16
16
|
* of the deploy overlap points at the alternate port. Pure, in-memory only - the stored routing
|
|
17
17
|
* config is never modified, and this must never be applied to data that gets persisted. */
|
|
18
18
|
export declare function applyDeployRemap(routing: RemoteConfig): RemoteConfig;
|
|
19
|
+
/** A stamp of the current remap interpretation, advertised in ping responses - so every connected
|
|
20
|
+
* client learns of a takeover within one ping interval, instead of waiting for its config poll
|
|
21
|
+
* or a write rejection. */
|
|
22
|
+
export declare function getTakeoverStamp(): string | undefined;
|
|
19
23
|
/** For the dying process: fast-write flush delays must never extend past this time, and after it
|
|
20
24
|
* fast writes flush immediately - so nothing is left in memory when the write window transfers. */
|
|
21
25
|
export declare function getFlushDeadline(): number | undefined;
|
|
@@ -392,6 +392,15 @@ export function applyDeployRemap(routing: RemoteConfig): RemoteConfig {
|
|
|
392
392
|
return { version: routing.version, sources };
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
/** A stamp of the current remap interpretation, advertised in ping responses - so every connected
|
|
396
|
+
* client learns of a takeover within one ping interval, instead of waiting for its config poll
|
|
397
|
+
* or a write rejection. */
|
|
398
|
+
export function getTakeoverStamp(): string | undefined {
|
|
399
|
+
let remap = current.remap;
|
|
400
|
+
if (!remap) return undefined;
|
|
401
|
+
return JSON.stringify(remap);
|
|
402
|
+
}
|
|
403
|
+
|
|
395
404
|
/** For the dying process: fast-write flush delays must never extend past this time, and after it
|
|
396
405
|
* fast writes flush immediately - so nothing is left in memory when the write window transfers. */
|
|
397
406
|
export function getFlushDeadline(): number | undefined {
|