fix(core): proper exit cleanup in json file
This commit is contained in:
parent
c95b5b70be
commit
02a6a0e133
5 changed files with 81 additions and 14 deletions
|
@ -15,6 +15,7 @@
|
||||||
"./src/utils/platform/transport.js": "./src/utils/platform/transport.web.js",
|
"./src/utils/platform/transport.js": "./src/utils/platform/transport.web.js",
|
||||||
"./src/utils/platform/logging.js": "./src/utils/platform/logging.web.js",
|
"./src/utils/platform/logging.js": "./src/utils/platform/logging.web.js",
|
||||||
"./src/utils/platform/random.js": "./src/utils/platform/random.web.js",
|
"./src/utils/platform/random.js": "./src/utils/platform/random.web.js",
|
||||||
|
"./src/utils/platform/exit-hook.js": "./src/utils/platform/exit-hook.web.js",
|
||||||
"./src/storage/json-file.js": false
|
"./src/storage/json-file.js": false
|
||||||
},
|
},
|
||||||
"distOnlyFields": {
|
"distOnlyFields": {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
|
|
||||||
|
import { beforeExit } from '../utils/index.js'
|
||||||
import { JsonMemoryStorage } from './json.js'
|
import { JsonMemoryStorage } from './json.js'
|
||||||
|
|
||||||
const EVENTS = ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SIGTERM']
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mtcute storage that stores data in a JSON file.
|
* mtcute storage that stores data in a JSON file.
|
||||||
*
|
*
|
||||||
|
@ -20,7 +19,7 @@ const EVENTS = ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SI
|
||||||
export class JsonFileStorage extends JsonMemoryStorage {
|
export class JsonFileStorage extends JsonMemoryStorage {
|
||||||
private readonly _filename: string
|
private readonly _filename: string
|
||||||
private readonly _safe: boolean
|
private readonly _safe: boolean
|
||||||
private readonly _cleanup: boolean
|
private readonly _cleanupUnregister?: () => void
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
filename: string,
|
filename: string,
|
||||||
|
@ -50,11 +49,9 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
||||||
|
|
||||||
this._filename = filename
|
this._filename = filename
|
||||||
this._safe = params?.safe ?? true
|
this._safe = params?.safe ?? true
|
||||||
this._cleanup = params?.cleanup ?? true
|
|
||||||
|
|
||||||
if (this._cleanup) {
|
if (params?.cleanup !== false) {
|
||||||
this._onProcessExit = this._onProcessExit.bind(this)
|
this._cleanupUnregister = beforeExit(() => this._onProcessExit())
|
||||||
EVENTS.forEach((event) => process.on(event, this._onProcessExit))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,12 +79,8 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private _processExitHandled = false
|
|
||||||
private _onProcessExit(): void {
|
private _onProcessExit(): void {
|
||||||
// on exit handler must be synchronous, thus we use sync methods here
|
// on exit handler must be synchronous, thus we use sync methods here
|
||||||
if (this._processExitHandled) return
|
|
||||||
this._processExitHandled = true
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(this._filename, this._saveJson())
|
fs.writeFileSync(this._filename, this._saveJson())
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
@ -100,8 +93,6 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
if (this._cleanup) {
|
this._cleanupUnregister?.()
|
||||||
EVENTS.forEach((event) => process.off(event, this._onProcessExit))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ export * from './lru-map.js'
|
||||||
export * from './lru-set.js'
|
export * from './lru-set.js'
|
||||||
export * from './misc-utils.js'
|
export * from './misc-utils.js'
|
||||||
export * from './peer-utils.js'
|
export * from './peer-utils.js'
|
||||||
|
export * from './platform/exit-hook.js'
|
||||||
export * from './sorted-array.js'
|
export * from './sorted-array.js'
|
||||||
export * from './string-session.js'
|
export * from './string-session.js'
|
||||||
export * from './tl-json.js'
|
export * from './tl-json.js'
|
||||||
|
|
53
packages/core/src/utils/platform/exit-hook.ts
Normal file
53
packages/core/src/utils/platform/exit-hook.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// roughly based on https://github.com/sindresorhus/exit-hook/blob/main/index.js, MIT license
|
||||||
|
|
||||||
|
let installed = false
|
||||||
|
let handled = false
|
||||||
|
|
||||||
|
const callbacks = new Set<() => void>()
|
||||||
|
|
||||||
|
function exit(shouldManuallyExit: boolean, signal: number, event: string) {
|
||||||
|
return function eventHandler() {
|
||||||
|
if (handled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handled = true
|
||||||
|
|
||||||
|
const exitCode = 128 + signal
|
||||||
|
|
||||||
|
for (const callback of callbacks) {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldManuallyExit) {
|
||||||
|
// if the user has some custom handlers after us, we don't want to exit the process
|
||||||
|
|
||||||
|
const listeners = process.rawListeners(event)
|
||||||
|
const idx = listeners.indexOf(eventHandler)
|
||||||
|
|
||||||
|
if (idx === listeners.length - 1) {
|
||||||
|
process.exit(exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function beforeExit(fn: () => void): () => void {
|
||||||
|
// unsupported platform
|
||||||
|
if (typeof process === 'undefined') return () => {}
|
||||||
|
|
||||||
|
if (!installed) {
|
||||||
|
installed = true
|
||||||
|
|
||||||
|
process.on('beforeExit', exit(true, -128, 'beforeExit'))
|
||||||
|
process.on('SIGINT', exit(true, 2, 'SIGINT'))
|
||||||
|
process.on('SIGTERM', exit(true, 15, 'SIGINT'))
|
||||||
|
process.on('exit', exit(false, 15, 'exit'))
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks.add(fn)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
callbacks.delete(fn)
|
||||||
|
}
|
||||||
|
}
|
21
packages/core/src/utils/platform/exit-hook.web.ts
Normal file
21
packages/core/src/utils/platform/exit-hook.web.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const callbacks = new Set<() => void>()
|
||||||
|
|
||||||
|
let registered = false
|
||||||
|
|
||||||
|
export function beforeExit(fn: () => void): () => void {
|
||||||
|
if (!registered) {
|
||||||
|
registered = true
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
for (const callback of callbacks) {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks.add(fn)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
callbacks.delete(fn)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue