handle "busy" error while reloading config files

Massimo Melina committed Dec 20, 2021 at 13:25 UTC 340cffc46ce6afedf0c1d8d511ea8d8733484103
4 files changed +20 -9
dev-notes.md
-1
@@ -1,5 +1,4 @@
1 # To do
2 -- when reloading vfs wait for it to be unlocked
2 - sticky breadcrumbs
3 - filter list
4 - search
src/misc.ts
+15 -2
@@ -1,4 +1,4 @@
1 -import { stat } from 'fs/promises'
1 +import fs from 'fs/promises'
2 import glob from 'fast-glob'
3 import { objSameKeys } from './obj'
4
@@ -11,7 +11,7 @@ export function wantArray(x:any) {
11 }
12
13 export async function isDirectory(path: string) {
14 - try { return (await stat(path)).isDirectory() }
14 + try { return (await fs.stat(path)).isDirectory() }
15 catch(e) { return false }
16 }
17
@@ -26,3 +26,16 @@ export function prefix(pre:string, v:string|number, post:string='') {
26 export function setHidden(dest: object, src:object) {
27 Object.defineProperties(dest, objSameKeys(src, value => ({ enumerable:false, value })))
28 }
29 +
30 +export function wait(ms: number) {
31 + return new Promise(res=> setTimeout(res,ms))
32 +}
33 +
34 +export async function readFileBusy(path: string): Promise<string> {
35 + return fs.readFile(path, 'utf8').catch(e => {
36 + if ((e as any)?.code !== 'EBUSY')
37 + throw e
38 + console.debug('busy')
39 + return wait(100).then(()=> readFileBusy(path))
40 + })
41 +}
src/perm.ts
+3 -4
@@ -4,7 +4,7 @@ import _ from 'lodash'
4 import yaml from 'yaml'
5 import { hashPassword, verifyPassword } from './crypt'
6 import { argv } from './const'
7 -import { setHidden } from './misc'
7 +import { readFileBusy, setHidden } from './misc'
8 import { SESSION_COOKIE } from './apis'
9 import { sessions } from './sessions'
10 import Koa from 'koa'
@@ -39,15 +39,14 @@ async function load() {
39 doing = true
40 try {
41 console.debug('loading', PATH)
42 - let file
42 + let res
43 try {
44 - file = await fs.readFile(PATH, 'utf8')
44 + res = yaml.parse(await readFileBusy(PATH))
45 }
46 catch(e){
47 console.warn('cannot read', PATH, e)
48 return
49 }
50 - const res = yaml.parse(file)
50 // we should validate content here
51 if (!res?.accounts)
52 return accounts = {}
src/vfs.ts
+2 -2
@@ -4,7 +4,7 @@ import fs from 'fs/promises'
4 import { FSWatcher, watch } from 'fs'
5 import { dirname, basename } from 'path'
6 import { isMatch } from 'micromatch'
7 -import { complySlashes, prefix } from './misc'
7 +import { complySlashes, prefix, readFileBusy } from './misc'
8 import { getCurrentUser } from './perm'
9 import Koa from 'koa'
10
@@ -49,7 +49,7 @@ export class Vfs {
49 async load(path: string, watchFile:boolean=true) {
50 console.debug('loading',path)
51 try {
52 - const data = await fs.readFile(path, 'utf8')
52 + const data = await readFileBusy(path)
53 this.root = yaml.parse(data)
54 // we should validate content now
55 }