実現したいこと
wait中にプログラムがシグナル(SIGINT/SIGTERM)を受信した場合に、速やかにタイマーを解除したい。ただし、タイマー強制解除は例外として受け取ることで、終了処理を書けるようにしたい。
コード
class ProcessMonitor {
protected readonly abortController = new AbortController()
constructor() {
process.on("SIGINT", () => {
this.abortController.abort();
});
process.on("SIGTERM", () => {
this.abortController.abort();
});
}
async wait(ms: number) {
const {signal} = this.abortController
signal.throwIfAborted()
await new Promise<void>((resolve, reject) => {
const type = "abort"
const listener = () => {
// setTimeout was aborted
signal.removeEventListener(type, listener)
reject(new DOMException("Aborted during wait", "AbortError"))
}
signal.addEventListener(type, listener);
// Call setTimeout with signal. Callback won't be fired when signalled.
setTimeout(() => {
// setTimeout was not aborted.
signal.removeEventListener(type, listener)
resolve()
}, ms, {signal})
})
}
get isTerminating() {
return this.abortController.signal.aborted
}
get isRunning() {
return !this.isTerminating
}
}
利用例
こちらの記事を書いているときに思いついたテクニックです。
https://qiita.com/tomohisaota/items/8900c96d299f4a02edf3
async run() {
this.isRunning = true
try {
while (processMonitor.isRunning) {
this.count++
if (this.count >= this.max) {
break
}
this.setNeedsUpdate()
await processMonitor.wait(this.interval)
}
} catch (e) {
if (e instanceof DOMException) {
if (e.name === "AbortError") {
return
}
}
throw e
}
this.isRunning = false
this.isCompleted = true
this.setNeedsUpdate()
}
希望者がいればもう少し詳しく解説します。