Serialize workspace registry persists
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
import { promises as fs } from 'node:fs'
|
import { promises as fs } from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ class FileBackedRegistry<TRecord extends RegistryRecord> {
|
|||||||
private readonly getId: (record: TRecord) => string
|
private readonly getId: (record: TRecord) => string
|
||||||
private loaded = false
|
private loaded = false
|
||||||
private readonly cache = new Map<string, TRecord>()
|
private readonly cache = new Map<string, TRecord>()
|
||||||
|
private persistQueue: Promise<void> = Promise.resolve()
|
||||||
|
|
||||||
constructor(options: {
|
constructor(options: {
|
||||||
filePath: string
|
filePath: string
|
||||||
@@ -103,7 +105,7 @@ class FileBackedRegistry<TRecord extends RegistryRecord> {
|
|||||||
await this.load()
|
await this.load()
|
||||||
const parsed = this.schema.parse(record)
|
const parsed = this.schema.parse(record)
|
||||||
this.cache.set(this.getId(parsed), parsed)
|
this.cache.set(this.getId(parsed), parsed)
|
||||||
await this.persist()
|
await this.enqueuePersist()
|
||||||
}
|
}
|
||||||
|
|
||||||
async archive(id: string, archivedAt: string): Promise<void> {
|
async archive(id: string, archivedAt: string): Promise<void> {
|
||||||
@@ -118,7 +120,7 @@ class FileBackedRegistry<TRecord extends RegistryRecord> {
|
|||||||
archivedAt,
|
archivedAt,
|
||||||
})
|
})
|
||||||
this.cache.set(id, next)
|
this.cache.set(id, next)
|
||||||
await this.persist()
|
await this.enqueuePersist()
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
@@ -126,7 +128,7 @@ class FileBackedRegistry<TRecord extends RegistryRecord> {
|
|||||||
if (!this.cache.delete(id)) {
|
if (!this.cache.delete(id)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await this.persist()
|
await this.enqueuePersist()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async load(): Promise<void> {
|
private async load(): Promise<void> {
|
||||||
@@ -153,10 +155,16 @@ class FileBackedRegistry<TRecord extends RegistryRecord> {
|
|||||||
private async persist(): Promise<void> {
|
private async persist(): Promise<void> {
|
||||||
const records = Array.from(this.cache.values())
|
const records = Array.from(this.cache.values())
|
||||||
await fs.mkdir(path.dirname(this.filePath), { recursive: true })
|
await fs.mkdir(path.dirname(this.filePath), { recursive: true })
|
||||||
const tempPath = `${this.filePath}.${process.pid}.${Date.now()}.tmp`
|
const tempPath = `${this.filePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`
|
||||||
await fs.writeFile(tempPath, JSON.stringify(records, null, 2), 'utf8')
|
await fs.writeFile(tempPath, JSON.stringify(records, null, 2), 'utf8')
|
||||||
await fs.rename(tempPath, this.filePath)
|
await fs.rename(tempPath, this.filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async enqueuePersist(): Promise<void> {
|
||||||
|
const nextPersist = this.persistQueue.then(() => this.persist())
|
||||||
|
this.persistQueue = nextPersist.catch(() => {})
|
||||||
|
await nextPersist
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileBackedProjectRegistry
|
export class FileBackedProjectRegistry
|
||||||
|
|||||||
Reference in New Issue
Block a user