querysub 0.566.0 → 0.568.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/appSecrets.ts
CHANGED
|
@@ -24,7 +24,7 @@ export const getCloudflareCreds = lazy(async (): Promise<{ key: string; email: s
|
|
|
24
24
|
/** Serves the secret keys sliftutils' getSecret expects, reading them the way querysub already does: backblaze creds off disk (getBackblazePath), cloudflare creds from the keys archives bucket (with its local file fallback). */
|
|
25
25
|
export async function getAppSecret(key: string): Promise<string | undefined> {
|
|
26
26
|
// Import query sub so our logs go to our actual log server. Otherwise we won't know if we get any errors.
|
|
27
|
-
|
|
27
|
+
Querysub;
|
|
28
28
|
if (key.startsWith("backblaze.json.")) {
|
|
29
29
|
let creds = JSON.parse(fs.readFileSync(getBackblazePath(), "utf8")) as { applicationKeyId?: string; applicationKey?: string };
|
|
30
30
|
if (key === "backblaze.json.applicationKeyId") return creds.applicationKeyId;
|
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@ import { PromiseObj } from "../promise";
|
|
|
26
26
|
import path from "path";
|
|
27
27
|
import { fsExistsAsync } from "../fs";
|
|
28
28
|
import { ALIVE_WINDOW_FOREVER, ParametersTimelineEntry, syncParametersTimelineFiles } from "./parametersTimeline";
|
|
29
|
-
import { getScreenName, getFutureScreenName, getTmuxPrefix, getScreenState, isScreenRunningProcess, getProcessStartTime, ensureProcessRecord, runScreenCommand, killScreen, streamProcessOutput } from "./processManager";
|
|
29
|
+
import { getScreenName, getFutureScreenName, getRetiringScreenName, getTmuxPrefix, getScreenState, isScreenRunningProcess, getProcessStartTime, ensureProcessRecord, runScreenCommand, killScreen, streamProcessOutput } from "./processManager";
|
|
30
30
|
import { ProcessRecord, syncProcessRecords, writeProcessRecord, listProcessRecords, getProcessLogPath } from "./processLogs";
|
|
31
31
|
|
|
32
32
|
|
|
@@ -339,11 +339,17 @@ async function takeoverFutureScreen(config: {
|
|
|
339
339
|
// The rename makes the future name vanish, but the caller's original screen list still has it — mark it used so the unused-screen cleanup doesn't try to kill a nonexistent session
|
|
340
340
|
config.screenNamesUsed.add(futureScreenName);
|
|
341
341
|
if (screenStateMap.has(canonicalScreenName)) {
|
|
342
|
-
|
|
342
|
+
// The old screen is moved aside rather than waited on: the canonical name is free immediately, and its shutdown (Ctrl+C, then the hard kill) runs on its own without holding up this service or the next one.
|
|
343
|
+
let retiringScreenName = getRetiringScreenName(canonicalScreenName, Date.now());
|
|
344
|
+
let prefix = getTmuxPrefix();
|
|
345
|
+
await runPromise(`${prefix}tmux rename-session -t ${canonicalScreenName} ${retiringScreenName}`);
|
|
343
346
|
screenStateMap.delete(canonicalScreenName);
|
|
347
|
+
// Kept out of the unused-screen sweep, which would kill it a second time while it is already winding down
|
|
348
|
+
config.screenNamesUsed.add(retiringScreenName);
|
|
349
|
+
void killScreen({ screenName: retiringScreenName, skipNodeIdRemoval: true });
|
|
344
350
|
let oldNodeId = takeoverOldNodeIds.get(canonicalScreenName);
|
|
345
351
|
if (oldNodeId) {
|
|
346
|
-
|
|
352
|
+
void forceRemoveNode(oldNodeId);
|
|
347
353
|
}
|
|
348
354
|
}
|
|
349
355
|
takeoverOldNodeIds.delete(canonicalScreenName);
|
|
@@ -429,7 +435,8 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
429
435
|
}
|
|
430
436
|
}
|
|
431
437
|
|
|
432
|
-
|
|
438
|
+
// Services run concurrently: each has its own folders, its own screens and its own records, and yarn install takes a network mutex, so there is nothing for them to serialize behind. One slow service (a git sync, a yarn install, a screen taking its full shutdown grace) no longer delays every service after it.
|
|
439
|
+
await Promise.all(recordStates.map(async ({ record, config, releaseTime, overlapTime, killTime, releaseInFlight, isPrepTime, isOverlapTime }) => {
|
|
433
440
|
if (releaseInFlight) {
|
|
434
441
|
upcomingReleases.push({ releaseTime, overlapTime });
|
|
435
442
|
console.log(magenta(`Release in flight for ${record.serviceId} (${record.parameters.key}): the new version starts at ${new Date(releaseTime).toLocaleString()}${isOverlapTime && " (overlap running)" || ""}, the old instances are killed at ${new Date(killTime).toLocaleString()}`));
|
|
@@ -460,7 +467,7 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
460
467
|
}
|
|
461
468
|
}
|
|
462
469
|
}
|
|
463
|
-
if (!config.parameters.deploy)
|
|
470
|
+
if (!config.parameters.deploy) return;
|
|
464
471
|
let matchedTargets = getMachineTargets(config.parameters).filter(target => target.machineId === machineId);
|
|
465
472
|
for (let i = 0; i < matchedTargets.length; i++) {
|
|
466
473
|
// Each instance runs the command with its own entry's template variables resolved, so the per-instance parameters (written to parameters.json and compared for restarts) carry the resolved command.
|
|
@@ -512,13 +519,13 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
512
519
|
};
|
|
513
520
|
|
|
514
521
|
if (releaseInFlight) {
|
|
515
|
-
// Tell the running instance when it will be shut down, so it (and everything talking to it) can wind down gracefully. Once the future instance may have started, the folder's nodeId file can belong to the NEW process, so from then on only the stashed old nodeId is safe to notify.
|
|
522
|
+
// Tell the running instance when it will be shut down, so it (and everything talking to it) can wind down gracefully. Fire and forget: it is a courtesy to the process, and nothing about taking it down may wait on a call to the process we are taking down. Once the future instance may have started, the folder's nodeId file can belong to the NEW process, so from then on only the stashed old nodeId is safe to notify.
|
|
516
523
|
if (!isOverlapTime) {
|
|
517
|
-
|
|
524
|
+
void notifyServiceShutdown(screenName, killTime);
|
|
518
525
|
} else {
|
|
519
526
|
let oldNodeId = takeoverOldNodeIds.get(screenName);
|
|
520
527
|
if (oldNodeId) {
|
|
521
|
-
|
|
528
|
+
void notifyNodeShutdown(screenName, oldNodeId, killTime);
|
|
522
529
|
}
|
|
523
530
|
}
|
|
524
531
|
} else {
|
|
@@ -690,11 +697,12 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
690
697
|
lastLaunchedTimePerService.set(config.serviceId, lastLaunchedTime);
|
|
691
698
|
launchesPerService.set(config.serviceId, launchCount);
|
|
692
699
|
}
|
|
693
|
-
}
|
|
700
|
+
}));
|
|
694
701
|
|
|
695
702
|
for (let { screenName } of screenState) {
|
|
696
703
|
if (screenNamesUsed.has(screenName)) continue;
|
|
697
|
-
|
|
704
|
+
// Detached, so a screen that takes its full grace period to go down doesn't hold up the end of the resync
|
|
705
|
+
void killScreen({
|
|
698
706
|
screenName,
|
|
699
707
|
});
|
|
700
708
|
}
|
|
@@ -24,6 +24,10 @@ const SCREEN_SUFFIX = "-dply";
|
|
|
24
24
|
export function getScreenName(config: { serviceKey: string; index: number }): string {
|
|
25
25
|
return `${config.serviceKey}-${config.index}${SCREEN_SUFFIX}`.replace(/[^a-zA-Z0-9\-_]/g, "_");
|
|
26
26
|
}
|
|
27
|
+
/** The name an outgoing screen is moved to so the new process can take the canonical name at once, instead of anything waiting for the old process to wind down. Keeps the suffix, so it is still a screen we know about. */
|
|
28
|
+
export function getRetiringScreenName(canonicalScreenName: string, at: number): string {
|
|
29
|
+
return canonicalScreenName.slice(0, -SCREEN_SUFFIX.length) + `-retiring-${at}` + SCREEN_SUFFIX;
|
|
30
|
+
}
|
|
27
31
|
// The new version's screen during a release, in the SAME folder as the canonical screen: created (just echoing when it will start) shortly before releaseTime, started at releaseTime, and renamed to the canonical screen name once the old screen is killed at releaseTime + overlapTime.
|
|
28
32
|
export function getFutureScreenName(canonicalScreenName: string): string {
|
|
29
33
|
return canonicalScreenName.slice(0, -SCREEN_SUFFIX.length) + "-future" + SCREEN_SUFFIX;
|