@hardlydifficult/daemon 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/dist/createTeardown.d.ts +30 -0
- package/dist/createTeardown.d.ts.map +1 -0
- package/dist/createTeardown.js +65 -0
- package/dist/createTeardown.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/runContinuousLoop.d.ts +34 -0
- package/dist/runContinuousLoop.d.ts.map +1 -0
- package/dist/runContinuousLoop.js +98 -0
- package/dist/runContinuousLoop.js.map +1 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# @hardlydifficult/teardown
|
|
2
|
+
|
|
3
|
+
Idempotent resource teardown with signal trapping. Register cleanup functions once at resource creation time — all exit paths call a single `run()`.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hardlydifficult/teardown
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createTeardown } from "@hardlydifficult/teardown";
|
|
15
|
+
|
|
16
|
+
const teardown = createTeardown();
|
|
17
|
+
teardown.add(() => server.stop());
|
|
18
|
+
teardown.add(() => db.close());
|
|
19
|
+
teardown.trapSignals();
|
|
20
|
+
|
|
21
|
+
// Any manual exit path:
|
|
22
|
+
await teardown.run();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Creating a Teardown Registry
|
|
26
|
+
|
|
27
|
+
Use `createTeardown()` to create a new teardown registry that manages cleanup functions.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { createTeardown } from "@hardlydifficult/teardown";
|
|
31
|
+
|
|
32
|
+
const teardown = createTeardown();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Registering Cleanup Functions
|
|
36
|
+
|
|
37
|
+
Call `add()` to register a cleanup function. Functions run in LIFO order (last added runs first). The `add()` method returns an unregister function for selective cleanup.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
const teardown = createTeardown();
|
|
41
|
+
|
|
42
|
+
// Register sync cleanup
|
|
43
|
+
teardown.add(() => {
|
|
44
|
+
console.log("Closing server");
|
|
45
|
+
server.stop();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Register async cleanup
|
|
49
|
+
teardown.add(async () => {
|
|
50
|
+
console.log("Closing database");
|
|
51
|
+
await db.close();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Unregister a specific function
|
|
55
|
+
const unregister = teardown.add(() => {
|
|
56
|
+
console.log("This won't run");
|
|
57
|
+
});
|
|
58
|
+
unregister();
|
|
59
|
+
|
|
60
|
+
await teardown.run();
|
|
61
|
+
// Output:
|
|
62
|
+
// Closing database
|
|
63
|
+
// Closing server
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Running Teardown
|
|
67
|
+
|
|
68
|
+
Call `run()` to execute all registered cleanup functions in LIFO order. The method is idempotent — subsequent calls are no-ops.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const teardown = createTeardown();
|
|
72
|
+
teardown.add(() => console.log("cleanup"));
|
|
73
|
+
|
|
74
|
+
await teardown.run();
|
|
75
|
+
// Output: cleanup
|
|
76
|
+
|
|
77
|
+
await teardown.run();
|
|
78
|
+
// No output (idempotent)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Signal Trapping
|
|
82
|
+
|
|
83
|
+
Call `trapSignals()` to automatically run teardown when the process receives SIGTERM or SIGINT signals. Returns an untrap function to remove signal handlers.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const teardown = createTeardown();
|
|
87
|
+
teardown.add(() => server.stop());
|
|
88
|
+
|
|
89
|
+
// Wire SIGTERM/SIGINT to run() then process.exit(0)
|
|
90
|
+
const untrap = teardown.trapSignals();
|
|
91
|
+
|
|
92
|
+
// Later, if needed:
|
|
93
|
+
untrap();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Error Resilience
|
|
97
|
+
|
|
98
|
+
Each teardown function is wrapped in try/catch. Errors don't block remaining teardowns — all functions run regardless of failures.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const teardown = createTeardown();
|
|
102
|
+
|
|
103
|
+
teardown.add(() => {
|
|
104
|
+
throw new Error("First cleanup fails");
|
|
105
|
+
});
|
|
106
|
+
teardown.add(() => {
|
|
107
|
+
console.log("Second cleanup still runs");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await teardown.run();
|
|
111
|
+
// Output: Second cleanup still runs
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Behavior Reference
|
|
115
|
+
|
|
116
|
+
| Behavior | Details |
|
|
117
|
+
|----------|---------|
|
|
118
|
+
| **LIFO order** | Teardowns run in reverse registration order (last added runs first) |
|
|
119
|
+
| **Idempotent** | `run()` executes once; subsequent calls are no-ops |
|
|
120
|
+
| **Error resilient** | Each function is wrapped in try/catch; failures don't block remaining teardowns |
|
|
121
|
+
| **Safe unregister** | `add()` returns an unregister function; safe to call multiple times |
|
|
122
|
+
| **Post-run add** | `add()` after `run()` is a silent no-op |
|
|
123
|
+
| **Duplicate safe** | Same function added twice runs twice; unregister only removes its own registration |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotent resource teardown with signal trapping
|
|
3
|
+
*
|
|
4
|
+
* Register cleanup functions once at resource creation time.
|
|
5
|
+
* All exit paths call a single `run()` — no duplication, no missed resources.
|
|
6
|
+
*/
|
|
7
|
+
export interface Teardown {
|
|
8
|
+
/** Register a teardown function. Returns an unregister function. */
|
|
9
|
+
add(fn: () => void | Promise<void>): () => void;
|
|
10
|
+
/** Run all teardown functions in LIFO order. Idempotent: second call is a no-op. */
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
/** Wire SIGTERM/SIGINT to run() then process.exit(0). Returns an untrap function. */
|
|
13
|
+
trapSignals(): () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a teardown registry
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const teardown = createTeardown();
|
|
21
|
+
* teardown.add(() => server.stop());
|
|
22
|
+
* teardown.add(() => db.close());
|
|
23
|
+
* teardown.trapSignals();
|
|
24
|
+
*
|
|
25
|
+
* // Any manual exit path:
|
|
26
|
+
* await teardown.run();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function createTeardown(): Teardown;
|
|
30
|
+
//# sourceMappingURL=createTeardown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTeardown.d.ts","sourceRoot":"","sources":["../src/createTeardown.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,oEAAoE;IACpE,GAAG,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;IAChD,oFAAoF;IACpF,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,qFAAqF;IACrF,WAAW,IAAI,MAAM,IAAI,CAAC;CAC3B;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,IAAI,QAAQ,CAsDzC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTeardown = createTeardown;
|
|
4
|
+
/**
|
|
5
|
+
* Create a teardown registry
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const teardown = createTeardown();
|
|
10
|
+
* teardown.add(() => server.stop());
|
|
11
|
+
* teardown.add(() => db.close());
|
|
12
|
+
* teardown.trapSignals();
|
|
13
|
+
*
|
|
14
|
+
* // Any manual exit path:
|
|
15
|
+
* await teardown.run();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function createTeardown() {
|
|
19
|
+
const entries = [];
|
|
20
|
+
let hasRun = false;
|
|
21
|
+
const run = async () => {
|
|
22
|
+
if (hasRun) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
hasRun = true;
|
|
26
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
27
|
+
const entry = entries[i];
|
|
28
|
+
if (entry.removed) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
await entry.fn();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Swallow errors per-fn so remaining teardowns still run
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
add(fn) {
|
|
41
|
+
if (hasRun) {
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
43
|
+
return () => { };
|
|
44
|
+
}
|
|
45
|
+
const entry = { fn, removed: false };
|
|
46
|
+
entries.push(entry);
|
|
47
|
+
return () => {
|
|
48
|
+
entry.removed = true;
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
run,
|
|
52
|
+
trapSignals() {
|
|
53
|
+
const onSignal = () => {
|
|
54
|
+
void run().then(() => process.exit(0));
|
|
55
|
+
};
|
|
56
|
+
process.on("SIGTERM", onSignal);
|
|
57
|
+
process.on("SIGINT", onSignal);
|
|
58
|
+
return () => {
|
|
59
|
+
process.off("SIGTERM", onSignal);
|
|
60
|
+
process.off("SIGINT", onSignal);
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=createTeardown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTeardown.js","sourceRoot":"","sources":["../src/createTeardown.ts"],"names":[],"mappings":";;AAkCA,wCAsDC;AApED;;;;;;;;;;;;;GAaG;AACH,SAAgB,cAAc;IAC5B,MAAM,OAAO,GAAY,EAAE,CAAC;IAC5B,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;QACpC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QACD,MAAM,GAAG,IAAI,CAAC;QAEd,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,SAAS;YACX,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,EAAE,EAAE,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,yDAAyD;YAC3D,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,CAAC,EAA8B;YAChC,IAAI,MAAM,EAAE,CAAC;gBACX,gEAAgE;gBAChE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,KAAK,GAAU,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEpB,OAAO,GAAG,EAAE;gBACV,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;YACvB,CAAC,CAAC;QACJ,CAAC;QAED,GAAG;QAEH,WAAW;YACT,MAAM,QAAQ,GAAG,GAAS,EAAE;gBAC1B,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC,CAAC;YAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAE/B,OAAO,GAAG,EAAE;gBACV,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBACjC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAClC,CAAC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,GAC3B,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runContinuousLoop = exports.createTeardown = void 0;
|
|
4
|
+
var createTeardown_js_1 = require("./createTeardown.js");
|
|
5
|
+
Object.defineProperty(exports, "createTeardown", { enumerable: true, get: function () { return createTeardown_js_1.createTeardown; } });
|
|
6
|
+
var runContinuousLoop_js_1 = require("./runContinuousLoop.js");
|
|
7
|
+
Object.defineProperty(exports, "runContinuousLoop", { enumerable: true, get: function () { return runContinuousLoop_js_1.runContinuousLoop; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAoE;AAA3D,mHAAA,cAAc,OAAA;AACvB,+DAGgC;AAF9B,yHAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for graceful shutdown and continuous loop execution.
|
|
3
|
+
*
|
|
4
|
+
* This module provides interruptible sleep and continuous loop functionality with proper signal handling for
|
|
5
|
+
* SIGINT/SIGTERM.
|
|
6
|
+
*/
|
|
7
|
+
/** Options for running a continuous loop */
|
|
8
|
+
export interface ContinuousLoopOptions {
|
|
9
|
+
/** Interval between cycles in seconds */
|
|
10
|
+
intervalSeconds: number;
|
|
11
|
+
/**
|
|
12
|
+
* Callback to run on each cycle.
|
|
13
|
+
*
|
|
14
|
+
* @param isShutdownRequested - Function to check if shutdown has been requested during the cycle
|
|
15
|
+
* @returns Promise that resolves when the cycle is complete (return value is ignored)
|
|
16
|
+
*/
|
|
17
|
+
runCycle: (isShutdownRequested: () => boolean) => Promise<unknown>;
|
|
18
|
+
/** Optional callback for cleanup on shutdown */
|
|
19
|
+
onShutdown?: () => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run a function in a continuous loop with graceful shutdown support.
|
|
23
|
+
*
|
|
24
|
+
* Features:
|
|
25
|
+
*
|
|
26
|
+
* - Interruptible sleep that responds immediately to SIGINT/SIGTERM
|
|
27
|
+
* - Proper signal handler cleanup to prevent listener accumulation
|
|
28
|
+
* - Continues to next cycle even if current cycle fails
|
|
29
|
+
* - Passes shutdown check callback to runCycle for in-cycle interruption
|
|
30
|
+
*
|
|
31
|
+
* @param options - Configuration for the continuous loop
|
|
32
|
+
*/
|
|
33
|
+
export declare function runContinuousLoop(options: ContinuousLoopOptions): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=runContinuousLoop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runContinuousLoop.d.ts","sourceRoot":"","sources":["../src/runContinuousLoop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4CAA4C;AAC5C,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,mBAAmB,EAAE,MAAM,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAqCD;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAuDf"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared utilities for graceful shutdown and continuous loop execution.
|
|
4
|
+
*
|
|
5
|
+
* This module provides interruptible sleep and continuous loop functionality with proper signal handling for
|
|
6
|
+
* SIGINT/SIGTERM.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.runContinuousLoop = runContinuousLoop;
|
|
10
|
+
/**
|
|
11
|
+
* Creates an interruptible sleep that can be woken early by calling the returned cancel function.
|
|
12
|
+
*
|
|
13
|
+
* @returns An object with a promise that resolves after durationMs or when cancel() is called
|
|
14
|
+
*/
|
|
15
|
+
function createInterruptibleSleep(durationMs) {
|
|
16
|
+
let resolve = null;
|
|
17
|
+
let timeout = null;
|
|
18
|
+
const promise = new Promise((r) => {
|
|
19
|
+
resolve = r;
|
|
20
|
+
timeout = setTimeout(() => {
|
|
21
|
+
timeout = null;
|
|
22
|
+
resolve = null;
|
|
23
|
+
r();
|
|
24
|
+
}, durationMs);
|
|
25
|
+
});
|
|
26
|
+
const cancel = () => {
|
|
27
|
+
if (timeout !== null) {
|
|
28
|
+
clearTimeout(timeout);
|
|
29
|
+
timeout = null;
|
|
30
|
+
}
|
|
31
|
+
if (resolve !== null) {
|
|
32
|
+
resolve();
|
|
33
|
+
resolve = null;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return { promise, cancel };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Run a function in a continuous loop with graceful shutdown support.
|
|
40
|
+
*
|
|
41
|
+
* Features:
|
|
42
|
+
*
|
|
43
|
+
* - Interruptible sleep that responds immediately to SIGINT/SIGTERM
|
|
44
|
+
* - Proper signal handler cleanup to prevent listener accumulation
|
|
45
|
+
* - Continues to next cycle even if current cycle fails
|
|
46
|
+
* - Passes shutdown check callback to runCycle for in-cycle interruption
|
|
47
|
+
*
|
|
48
|
+
* @param options - Configuration for the continuous loop
|
|
49
|
+
*/
|
|
50
|
+
async function runContinuousLoop(options) {
|
|
51
|
+
const { intervalSeconds, runCycle, onShutdown } = options;
|
|
52
|
+
let shutdownRequested = false;
|
|
53
|
+
let cancelCurrentSleep = null;
|
|
54
|
+
const handleShutdown = (signal) => {
|
|
55
|
+
console.warn(`Received ${signal}, shutting down gracefully...`);
|
|
56
|
+
shutdownRequested = true;
|
|
57
|
+
if (cancelCurrentSleep !== null) {
|
|
58
|
+
cancelCurrentSleep();
|
|
59
|
+
cancelCurrentSleep = null;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const sigintHandler = () => {
|
|
63
|
+
handleShutdown("SIGINT");
|
|
64
|
+
};
|
|
65
|
+
const sigtermHandler = () => {
|
|
66
|
+
handleShutdown("SIGTERM");
|
|
67
|
+
};
|
|
68
|
+
process.on("SIGINT", sigintHandler);
|
|
69
|
+
process.on("SIGTERM", sigtermHandler);
|
|
70
|
+
const isShutdownRequested = () => shutdownRequested;
|
|
71
|
+
const shouldContinue = () => !shutdownRequested;
|
|
72
|
+
try {
|
|
73
|
+
while (shouldContinue()) {
|
|
74
|
+
try {
|
|
75
|
+
await runCycle(isShutdownRequested);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
79
|
+
console.error(`Cycle error: ${errorMessage}`);
|
|
80
|
+
}
|
|
81
|
+
if (!shouldContinue()) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
const sleep = createInterruptibleSleep(intervalSeconds * 1000);
|
|
85
|
+
cancelCurrentSleep = sleep.cancel;
|
|
86
|
+
await sleep.promise;
|
|
87
|
+
cancelCurrentSleep = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
process.off("SIGINT", sigintHandler);
|
|
92
|
+
process.off("SIGTERM", sigtermHandler);
|
|
93
|
+
if (onShutdown !== undefined) {
|
|
94
|
+
await onShutdown();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=runContinuousLoop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runContinuousLoop.js","sourceRoot":"","sources":["../src/runContinuousLoop.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/daemon",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"test:coverage": "vitest run --coverage",
|
|
14
|
+
"lint": "tsc --noEmit",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "25.2.3",
|
|
19
|
+
"typescript": "5.9.3",
|
|
20
|
+
"vitest": "4.0.18"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|