refactor: reduce startup mounting noise (#177)
- Skip mount early if volume is not in error or neither mounted - Error healthchecks early if volume is not mounted
This commit is contained in:
parent
a17da2562f
commit
fd5193b5e3
4 changed files with 97 additions and 66 deletions
|
|
@ -27,8 +27,10 @@ const mount = async (config: BackendConfig, path: string) => {
|
|||
return { status: BACKEND_STATUS.mounted };
|
||||
}
|
||||
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
if (status === "error") {
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
await fs.mkdir(path, { recursive: true });
|
||||
|
|
@ -64,16 +66,15 @@ const unmount = async (path: string) => {
|
|||
}
|
||||
|
||||
const run = async () => {
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch {
|
||||
logger.warn(`Path ${path} does not exist. Skipping unmount.`);
|
||||
const mount = await getMountForPath(path);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
logger.debug(`Path ${path} is not a mount point. Skipping unmount.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
}
|
||||
|
||||
await executeUnmount(path);
|
||||
|
||||
await fs.rmdir(path);
|
||||
await fs.rmdir(path).catch(() => {});
|
||||
|
||||
logger.info(`NFS volume at ${path} unmounted successfully.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
|
|
@ -89,13 +90,20 @@ const unmount = async (path: string) => {
|
|||
|
||||
const checkHealth = async (path: string) => {
|
||||
const run = async () => {
|
||||
logger.debug(`Checking health of NFS volume at ${path}...`);
|
||||
await fs.access(path);
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
const mount = await getMountForPath(path);
|
||||
|
||||
if (!mount || !mount.fstype.startsWith("nfs")) {
|
||||
throw new Error(`Path ${path} is not mounted as NFS.`);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
if (!mount.fstype.startsWith("nfs")) {
|
||||
throw new Error(`Path ${path} is not mounted as NFS (found ${mount.fstype}).`);
|
||||
}
|
||||
|
||||
logger.debug(`NFS volume at ${path} is healthy and mounted.`);
|
||||
|
|
@ -105,8 +113,11 @@ const checkHealth = async (path: string) => {
|
|||
try {
|
||||
return await withTimeout(run(), OPERATION_TIMEOUT, "NFS health check");
|
||||
} catch (error) {
|
||||
logger.error("NFS volume health check failed:", toMessage(error));
|
||||
return { status: BACKEND_STATUS.error, error: toMessage(error) };
|
||||
const message = toMessage(error);
|
||||
if (message !== "Volume is not mounted") {
|
||||
logger.error("NFS volume health check failed:", message);
|
||||
}
|
||||
return { status: BACKEND_STATUS.error, error: message };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ const mount = async (config: BackendConfig, path: string) => {
|
|||
return { status: BACKEND_STATUS.mounted };
|
||||
}
|
||||
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
if (status === "error") {
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
await fs.mkdir(path, { recursive: true });
|
||||
|
|
@ -76,15 +78,14 @@ const unmount = async (path: string) => {
|
|||
}
|
||||
|
||||
const run = async () => {
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch (e) {
|
||||
logger.warn(`Path ${path} does not exist. Skipping unmount.`, e);
|
||||
const mount = await getMountForPath(path);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
logger.debug(`Path ${path} is not a mount point. Skipping unmount.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
}
|
||||
|
||||
await executeUnmount(path);
|
||||
await fs.rmdir(path);
|
||||
await fs.rmdir(path).catch(() => {});
|
||||
|
||||
logger.info(`Rclone volume at ${path} unmounted successfully.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
|
|
@ -100,13 +101,20 @@ const unmount = async (path: string) => {
|
|||
|
||||
const checkHealth = async (path: string) => {
|
||||
const run = async () => {
|
||||
logger.debug(`Checking health of rclone volume at ${path}...`);
|
||||
await fs.access(path);
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
const mount = await getMountForPath(path);
|
||||
|
||||
if (!mount || mount.fstype !== "fuse.rclone") {
|
||||
throw new Error(`Path ${path} is not mounted as rclone.`);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
if (!mount.fstype.includes("rclone")) {
|
||||
throw new Error(`Path ${path} is not mounted as rclone (found ${mount.fstype}).`);
|
||||
}
|
||||
|
||||
logger.debug(`Rclone volume at ${path} is healthy and mounted.`);
|
||||
|
|
@ -116,8 +124,11 @@ const checkHealth = async (path: string) => {
|
|||
try {
|
||||
return await withTimeout(run(), OPERATION_TIMEOUT, "Rclone health check");
|
||||
} catch (error) {
|
||||
logger.error("Rclone volume health check failed:", toMessage(error));
|
||||
return { status: BACKEND_STATUS.error, error: toMessage(error) };
|
||||
const message = toMessage(error);
|
||||
if (message !== "Volume is not mounted") {
|
||||
logger.error("Rclone volume health check failed:", message);
|
||||
}
|
||||
return { status: BACKEND_STATUS.error, error: message };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ const mount = async (config: BackendConfig, path: string) => {
|
|||
return { status: BACKEND_STATUS.mounted };
|
||||
}
|
||||
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
if (status === "error") {
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
await fs.mkdir(path, { recursive: true });
|
||||
|
|
@ -80,16 +82,15 @@ const unmount = async (path: string) => {
|
|||
}
|
||||
|
||||
const run = async () => {
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch {
|
||||
logger.warn(`Path ${path} does not exist. Skipping unmount.`);
|
||||
const mount = await getMountForPath(path);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
logger.debug(`Path ${path} is not a mount point. Skipping unmount.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
}
|
||||
|
||||
await executeUnmount(path);
|
||||
|
||||
await fs.rmdir(path);
|
||||
await fs.rmdir(path).catch(() => {});
|
||||
|
||||
logger.info(`SMB volume at ${path} unmounted successfully.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
|
|
@ -105,13 +106,20 @@ const unmount = async (path: string) => {
|
|||
|
||||
const checkHealth = async (path: string) => {
|
||||
const run = async () => {
|
||||
logger.debug(`Checking health of SMB volume at ${path}...`);
|
||||
await fs.access(path);
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
const mount = await getMountForPath(path);
|
||||
|
||||
if (!mount || mount.fstype !== "cifs") {
|
||||
throw new Error(`Path ${path} is not mounted as CIFS/SMB.`);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
if (mount.fstype !== "cifs") {
|
||||
throw new Error(`Path ${path} is not mounted as CIFS/SMB (found ${mount.fstype}).`);
|
||||
}
|
||||
|
||||
logger.debug(`SMB volume at ${path} is healthy and mounted.`);
|
||||
|
|
@ -121,8 +129,11 @@ const checkHealth = async (path: string) => {
|
|||
try {
|
||||
return await withTimeout(run(), OPERATION_TIMEOUT, "SMB health check");
|
||||
} catch (error) {
|
||||
logger.error("SMB volume health check failed:", toMessage(error));
|
||||
return { status: BACKEND_STATUS.error, error: toMessage(error) };
|
||||
const message = toMessage(error);
|
||||
if (message !== "Volume is not mounted") {
|
||||
logger.error("SMB volume health check failed:", message);
|
||||
}
|
||||
return { status: BACKEND_STATUS.error, error: message };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { execFile as execFileCb } from "node:child_process";
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import { promisify } from "node:util";
|
||||
import { OPERATION_TIMEOUT } from "../../../core/constants";
|
||||
import { cryptoUtils } from "../../../utils/crypto";
|
||||
import { toMessage } from "../../../utils/errors";
|
||||
|
|
@ -12,8 +10,6 @@ import type { VolumeBackend } from "../backend";
|
|||
import { executeMount, executeUnmount } from "../utils/backend-utils";
|
||||
import { BACKEND_STATUS, type BackendConfig } from "~/schemas/volumes";
|
||||
|
||||
const execFile = promisify(execFileCb);
|
||||
|
||||
const mount = async (config: BackendConfig, path: string) => {
|
||||
logger.debug(`Mounting WebDAV volume ${path}...`);
|
||||
|
||||
|
|
@ -32,8 +28,10 @@ const mount = async (config: BackendConfig, path: string) => {
|
|||
return { status: BACKEND_STATUS.mounted };
|
||||
}
|
||||
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
if (status === "error") {
|
||||
logger.debug(`Trying to unmount any existing mounts at ${path} before mounting...`);
|
||||
await unmount(path);
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
await fs.mkdir(path, { recursive: true }).catch((err) => {
|
||||
|
|
@ -58,18 +56,9 @@ const mount = async (config: BackendConfig, path: string) => {
|
|||
|
||||
logger.debug(`Mounting WebDAV volume ${path}...`);
|
||||
|
||||
const args = ["-t", "davfs", source, path];
|
||||
const args = ["-t", "davfs", "-o", options.join(","), source, path];
|
||||
await executeMount(args);
|
||||
|
||||
const { stderr } = await execFile("mount", ["-t", "davfs", "-o", options.join(","), source, path], {
|
||||
timeout: OPERATION_TIMEOUT,
|
||||
maxBuffer: 1024 * 1024,
|
||||
});
|
||||
|
||||
if (stderr?.trim()) {
|
||||
logger.warn(stderr.trim());
|
||||
}
|
||||
|
||||
logger.info(`WebDAV volume at ${path} mounted successfully.`);
|
||||
return { status: BACKEND_STATUS.mounted };
|
||||
};
|
||||
|
|
@ -113,16 +102,15 @@ const unmount = async (path: string) => {
|
|||
}
|
||||
|
||||
const run = async () => {
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch (e) {
|
||||
logger.warn(`Path ${path} does not exist. Skipping unmount.`, e);
|
||||
const mount = await getMountForPath(path);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
logger.debug(`Path ${path} is not a mount point. Skipping unmount.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
}
|
||||
|
||||
await executeUnmount(path);
|
||||
|
||||
await fs.rmdir(path);
|
||||
await fs.rmdir(path).catch(() => {});
|
||||
|
||||
logger.info(`WebDAV volume at ${path} unmounted successfully.`);
|
||||
return { status: BACKEND_STATUS.unmounted };
|
||||
|
|
@ -138,13 +126,20 @@ const unmount = async (path: string) => {
|
|||
|
||||
const checkHealth = async (path: string) => {
|
||||
const run = async () => {
|
||||
logger.debug(`Checking health of WebDAV volume at ${path}...`);
|
||||
await fs.access(path);
|
||||
try {
|
||||
await fs.access(path);
|
||||
} catch {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
const mount = await getMountForPath(path);
|
||||
|
||||
if (!mount || mount.fstype !== "fuse") {
|
||||
throw new Error(`Path ${path} is not mounted as WebDAV.`);
|
||||
if (!mount || mount.mountPoint !== path) {
|
||||
throw new Error("Volume is not mounted");
|
||||
}
|
||||
|
||||
if (mount.fstype !== "fuse" && mount.fstype !== "davfs") {
|
||||
throw new Error(`Path ${path} is not mounted as WebDAV (found ${mount.fstype}).`);
|
||||
}
|
||||
|
||||
logger.debug(`WebDAV volume at ${path} is healthy and mounted.`);
|
||||
|
|
@ -154,8 +149,11 @@ const checkHealth = async (path: string) => {
|
|||
try {
|
||||
return await withTimeout(run(), OPERATION_TIMEOUT, "WebDAV health check");
|
||||
} catch (error) {
|
||||
logger.error("WebDAV volume health check failed:", toMessage(error));
|
||||
return { status: BACKEND_STATUS.error, error: toMessage(error) };
|
||||
const message = toMessage(error);
|
||||
if (message !== "Volume is not mounted") {
|
||||
logger.error("WebDAV volume health check failed:", message);
|
||||
}
|
||||
return { status: BACKEND_STATUS.error, error: message };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue