9d83255426
Adds isToleratedFsyncError, tolerantFsync (async, FileHandle), and tolerantFsyncSync (sync, fd) helpers that swallow filesystem-limitation errors during fsync (EPERM, EACCES, ENOTSUP, EINVAL) while still propagating real errors (EIO, ENOSPC, EBADF, etc.). Synced folders like iCloud Drive, OneDrive, and antivirus-locked files reject fsync with EPERM even though the underlying write+rename succeeded; for the runtime data this codebase persists, losing the durability hint is acceptable in exchange for not blocking the operation entirely. The helper is intentionally not barrel-exported (consumers import the file directly), matching the existing convention for write-file-atomically.
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import { fsyncSync } from "node:fs"
|
|
import type { FileHandle } from "node:fs/promises"
|
|
|
|
import { log } from "./logger"
|
|
|
|
const TOLERATED_FSYNC_CODES: ReadonlySet<string> = new Set([
|
|
"EPERM",
|
|
"EACCES",
|
|
"ENOTSUP",
|
|
"EINVAL",
|
|
])
|
|
|
|
export function isToleratedFsyncError(error: unknown): boolean {
|
|
if (!(error instanceof Error)) return false
|
|
const code = (error as NodeJS.ErrnoException).code
|
|
return code !== undefined && TOLERATED_FSYNC_CODES.has(code)
|
|
}
|
|
|
|
export async function tolerantFsync(
|
|
fileHandle: FileHandle,
|
|
contextLabel: string,
|
|
): Promise<void> {
|
|
try {
|
|
await fileHandle.sync()
|
|
} catch (error) {
|
|
if (!isToleratedFsyncError(error)) throw error
|
|
log("fsync skipped due to filesystem limitation", {
|
|
event: "fsync-skipped",
|
|
contextLabel,
|
|
code: (error as NodeJS.ErrnoException).code,
|
|
message: error instanceof Error ? error.message : String(error),
|
|
})
|
|
}
|
|
}
|
|
|
|
export function tolerantFsyncSync(
|
|
fileDescriptor: number,
|
|
contextLabel: string,
|
|
fsyncImpl: typeof fsyncSync = fsyncSync,
|
|
): void {
|
|
try {
|
|
fsyncImpl(fileDescriptor)
|
|
} catch (error) {
|
|
if (!isToleratedFsyncError(error)) throw error
|
|
log("fsync skipped due to filesystem limitation", {
|
|
event: "fsync-skipped",
|
|
contextLabel,
|
|
code: (error as NodeJS.ErrnoException).code,
|
|
message: error instanceof Error ? error.message : String(error),
|
|
})
|
|
}
|
|
}
|