backup engine internals - restic timeout and stack-dir capture
This commit is contained in:
9 files changed
+113
-152
No files matched your search
@@ -41,7 +41,9 @@ export interface MetadataFile {
|
||||
* @param resticArgs the full restic argv (starting with 'backup') — already
|
||||
* tag/exclude/flag-assembled by the caller.
|
||||
*/
|
||||
export function buildBackupScript(resticArgs: string[], stackDirProbe?: { volumeKey: string; composeFileName: string; label?: string; hostPath?: string }): string {
|
||||
import type { StackDirProbeHint } from './stackdir-plan';
|
||||
|
||||
export function buildBackupScript(resticArgs: string[], stackDirProbe?: { volumeKey: string; composeFileName: string; label?: string; hostPath?: string; hint?: StackDirProbeHint }): string {
|
||||
// restic runs backgrounded so the SIGINT-forwarding trap can reach it on cancel
|
||||
// (SIGINT lets restic release its repo lock; a SIGKILL orphans it and hangs the
|
||||
// next backup on --retry-lock). The kill-0 re-wait loop only fires when a signal
|
||||
@@ -61,14 +63,28 @@ export function buildBackupScript(resticArgs: string[], stackDirProbe?: { volume
|
||||
if (stackDirProbe) {
|
||||
const composePath = shellQuote(`/volumes/${stackDirProbe.volumeKey}/${stackDirProbe.composeFileName}`);
|
||||
const label = stackDirProbe.label ? ` ${stackDirProbe.label}` : '';
|
||||
// Name the REAL host path we mounted (<remote_stacks_dir>/<stack>) so the operator knows
|
||||
// exactly where to look, and what to do: redeploy the stack to stage its files there.
|
||||
const hostHint = stackDirProbe.hostPath
|
||||
? ` The stack folder is empty or missing at ${stackDirProbe.hostPath} on the Docker host - redeploy the stack to stage its files there.`
|
||||
: '';
|
||||
// The compose is missing under the host dir we bind-mounted. For a remote env (hawser or a
|
||||
// user-set path) tell the operator to point "Remote stack path (for backup)" at the real host
|
||||
// path; for a local stack a redeploy stages the files.
|
||||
const hint = stackDirProbe.hint;
|
||||
const remote = hint?.kind === 'hawser-defaulted' || hint?.kind === 'user-set';
|
||||
const where = remote ? hint.hostPath : stackDirProbe.hostPath;
|
||||
// "on <env>" when we know the environment name, else a plain "on the host".
|
||||
const on = remote && hint.envName ? ` on ${hint.envName}` : ` on the host`;
|
||||
// Name the EXACT settings location so the operator can go straight there.
|
||||
const settingsLoc = remote && hint.envName ? `Settings > Environments > ${hint.envName}` : `Settings > Environments`;
|
||||
const fix = remote
|
||||
? ` Set "Remote stack path (for backup)" in ${settingsLoc} to the real host path where this stack's files live.`
|
||||
: ` Redeploy the stack to stage its files there.`;
|
||||
const at = where ? ` in ${where}` : '';
|
||||
// Build the whole message as ONE string and shell-quote it so the operator-facing text
|
||||
// (which contains quotes, parens, and `>` - e.g. `"Remote stack path (for backup)"` and
|
||||
// `Settings > Environments > <env>`) can never break the `sh` syntax. The timestamp stays
|
||||
// a live $(date ...) OUTSIDE the quoted literal, concatenated in.
|
||||
const msg = `${label} STACKDIR PROBE FAILED: compose ${stackDirProbe.composeFileName} not found${at}${on}.${fix}`;
|
||||
probe =
|
||||
`if [ ! -f ${composePath} ]; then ` +
|
||||
`echo "[backup] $(date -u +%Y-%m-%dT%H:%M:%SZ)${label} STACKDIR PROBE FAILED: the stack's compose (${stackDirProbe.composeFileName}) is not present under the mounted stack dir.${hostHint} Refusing to write a silent-empty snapshot." 1>&2; ` +
|
||||
`echo "[backup] $(date -u +%Y-%m-%dT%H:%M:%SZ)"${shellQuote(msg)} 1>&2; ` +
|
||||
`exit 1; fi; `;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user