@radically-straightforward/utilities 1.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0 · 2024-04-09
4
+
5
+ - **Breaking Change:** Made `@radically-straightforward/utilities` truly independent of platform by extracting the Node.js especial treatment into `@radically-straightforward/node`.
6
+
3
7
  ## 1.2.2 · 2024-04-01
4
8
 
5
9
  - Added:
package/README.md CHANGED
@@ -16,69 +16,6 @@ import * as utilities from "@radically-straightforward/utilities";
16
16
 
17
17
  <!-- DOCUMENTATION START: ./source/index.mts -->
18
18
 
19
- ### `backgroundJob()`
20
-
21
- ```typescript
22
- export function backgroundJob(
23
- {
24
- interval,
25
- intervalVariance = 0.1,
26
- }: {
27
- interval: number;
28
- intervalVariance?: number;
29
- },
30
- job: () => void | Promise<void>,
31
- ): {
32
- run: () => void;
33
- stop: () => void;
34
- };
35
- ```
36
-
37
- Start a background job that runs every `interval`.
38
-
39
- This is different from `setInterval()` in the following ways:
40
-
41
- 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
42
-
43
- ```
44
- setInterval()
45
- | SLOW BACKGROUND JOB |
46
- | INTERVAL | SLOW BACKGROUND JOB |
47
- | INTERVAL | ...
48
-
49
- backgroundJob()
50
- | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
51
- ```
52
-
53
- 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
54
-
55
- 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
56
-
57
- 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
58
-
59
- 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
60
-
61
- **Example**
62
-
63
- ```javascript
64
- import * as utilities from "@radically-straightforward/utilities";
65
-
66
- const backgroundJob = utilities.backgroundJob(
67
- { interval: 3 * 1000 },
68
- async () => {
69
- console.log("backgroundJob(): Running background job...");
70
- await utilities.sleep(3 * 1000);
71
- console.log("backgroundJob(): ...finished running background job.");
72
- },
73
- );
74
- process.on("SIGTSTP", () => {
75
- backgroundJob.run();
76
- });
77
- console.log(
78
- "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
79
- );
80
- ```
81
-
82
19
  ### `sleep()`
83
20
 
84
21
  ```typescript
@@ -158,14 +95,6 @@ export const ISODateRegExp: RegExp;
158
95
 
159
96
  A regular expression that matches ISO dates, for example, `2024-04-01T14:19:48.162Z`.
160
97
 
161
- ### `localizedDateRegExp`
162
-
163
- ```typescript
164
- export const localizedDateRegExp: RegExp;
165
- ```
166
-
167
- A regular expression that matches localized dates, for example, `2024-04-01 15:20`.
168
-
169
98
  ### `Intern`
170
99
 
171
100
  ```typescript
@@ -307,4 +236,46 @@ Similar to `collections-deep-equal` but either incomplete, or lacking type defin
307
236
  - <https://twitter.com/swannodette/status/1067962983924539392>
308
237
  - <https://gist.github.com/modernserf/c000e62d40f678cf395e3f360b9b0e43>
309
238
 
239
+ ### `backgroundJob()`
240
+
241
+ ```typescript
242
+ export function backgroundJob(
243
+ {
244
+ interval,
245
+ onStop = () => {},
246
+ }: {
247
+ interval: number;
248
+ onStop?: () => void | Promise<void>;
249
+ },
250
+ job: () => void | Promise<void>,
251
+ ): {
252
+ run: () => Promise<void>;
253
+ stop: () => Promise<void>;
254
+ };
255
+ ```
256
+
257
+ > **Note:** This is a lower level utility. See `@radically-straightforward/node`’s and `@radically-straightforward/javascript`’s extensions to `backgroundJob()` that are better suited for their specific environments.
258
+
259
+ Start a background job that runs every `interval`.
260
+
261
+ `backgroundJob()` is different from `setInterval()` in the following ways:
262
+
263
+ 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
264
+
265
+ ```
266
+ setInterval()
267
+ | SLOW BACKGROUND JOB |
268
+ | INTERVAL | SLOW BACKGROUND JOB |
269
+ | INTERVAL | ...
270
+
271
+ backgroundJob()
272
+ | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
273
+ ```
274
+
275
+ 2. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of `0`).
276
+
277
+ 3. You may use `backgroundJob.stop()` to stop the background job. If the background job is in the middle of running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
278
+
279
+ 4. We introduce a random interval variance of 10% on top of the given `interval` to avoid many background jobs from starting at the same time and overloading the machine.
280
+
310
281
  <!-- DOCUMENTATION END: ./source/index.mts -->
package/build/index.d.mts CHANGED
@@ -1,56 +1,3 @@
1
- /**
2
- * Start a background job that runs every `interval`.
3
- *
4
- * This is different from `setInterval()` in the following ways:
5
- *
6
- * 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
7
- *
8
- * ```
9
- * setInterval()
10
- * | SLOW BACKGROUND JOB |
11
- * | INTERVAL | SLOW BACKGROUND JOB |
12
- * | INTERVAL | ...
13
- *
14
- * backgroundJob()
15
- * | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
16
- * ```
17
- *
18
- * 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
19
- *
20
- * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
21
- *
22
- * 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
23
- *
24
- * 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
25
- *
26
- * **Example**
27
- *
28
- * ```javascript
29
- * import * as utilities from "@radically-straightforward/utilities";
30
- *
31
- * const backgroundJob = utilities.backgroundJob(
32
- * { interval: 3 * 1000 },
33
- * async () => {
34
- * console.log("backgroundJob(): Running background job...");
35
- * await utilities.sleep(3 * 1000);
36
- * console.log("backgroundJob(): ...finished running background job.");
37
- * },
38
- * );
39
- * process.on("SIGTSTP", () => {
40
- * backgroundJob.run();
41
- * });
42
- * console.log(
43
- * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
44
- * );
45
- * ```
46
- */
47
- export declare function backgroundJob({ interval, intervalVariance, }: {
48
- interval: number;
49
- intervalVariance?: number;
50
- }, job: () => void | Promise<void>): {
51
- run: () => void;
52
- stop: () => void;
53
- };
54
1
  /**
55
2
  * A promisified version of `setTimeout()`. Bare-bones: It doesn’t even offer a way to `clearTimeout()`. Useful in JavaScript that may run in the browser—if you’re only targeting Node.js then you’re better served by [`timersPromises.setTimeout()`](https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options).
56
3
  */
@@ -100,10 +47,6 @@ export declare const emailRegExp: RegExp;
100
47
  * A regular expression that matches ISO dates, for example, `2024-04-01T14:19:48.162Z`.
101
48
  */
102
49
  export declare const ISODateRegExp: RegExp;
103
- /**
104
- * A regular expression that matches localized dates, for example, `2024-04-01 15:20`.
105
- */
106
- export declare const localizedDateRegExp: RegExp;
107
50
  /**
108
51
  * Utility type for `intern()`.
109
52
  */
@@ -236,4 +179,36 @@ export declare namespace intern {
236
179
  }>;
237
180
  }
238
181
  export declare const internSymbol: unique symbol;
182
+ /**
183
+ * > **Note:** This is a lower level utility. See `@radically-straightforward/node`’s and `@radically-straightforward/javascript`’s extensions to `backgroundJob()` that are better suited for their specific environments.
184
+ *
185
+ * Start a background job that runs every `interval`.
186
+ *
187
+ * `backgroundJob()` is different from `setInterval()` in the following ways:
188
+ *
189
+ * 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
190
+ *
191
+ * ```
192
+ * setInterval()
193
+ * | SLOW BACKGROUND JOB |
194
+ * | INTERVAL | SLOW BACKGROUND JOB |
195
+ * | INTERVAL | ...
196
+ *
197
+ * backgroundJob()
198
+ * | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
199
+ * ```
200
+ *
201
+ * 2. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of `0`).
202
+ *
203
+ * 3. You may use `backgroundJob.stop()` to stop the background job. If the background job is in the middle of running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
204
+ *
205
+ * 4. We introduce a random interval variance of 10% on top of the given `interval` to avoid many background jobs from starting at the same time and overloading the machine.
206
+ */
207
+ export declare function backgroundJob({ interval, onStop, }: {
208
+ interval: number;
209
+ onStop?: () => void | Promise<void>;
210
+ }, job: () => void | Promise<void>): {
211
+ run: () => Promise<void>;
212
+ stop: () => Promise<void>;
213
+ };
239
214
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,aAAa,CAC3B,EACE,QAAQ,EACR,gBAAsB,GACvB,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,GAAG,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC9B;IAAE,GAAG,EAAE,MAAM,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAwCvC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,GAAG,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAEnD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,wBAAyB,SAAQ,eAAe;;CAkB5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAI9C;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAAmD,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MACqB,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAA0C,CAAC;AAE7E;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,GAAG;IAAE,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,SAAS,GACT,IAAI,GACJ,MAAM,CAAC,OAAO,CAAC,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,wBAAgB,MAAM,CACpB,IAAI,SAAS,KAAK,CAAC,gBAAgB,CAAC,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAA;CAAE,EAC1E,KAAK,EAAE,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAyC3B;yBA3Ce,MAAM;;;;;;;;;;;;;;;;AA6CtB,eAAO,MAAM,YAAY,eAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,GAAG,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAEnD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,wBAAyB,SAAQ,eAAe;;CAkB5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAI9C;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAAmD,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MACqB,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,GAAG;IAAE,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,SAAS,GACT,IAAI,GACJ,MAAM,CAAC,OAAO,CAAC,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,wBAAgB,MAAM,CACpB,IAAI,SAAS,KAAK,CAAC,gBAAgB,CAAC,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAA;CAAE,EAC1E,KAAK,EAAE,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAyC3B;yBA3Ce,MAAM;;;;;;;;;;;;;;;;AA6CtB,eAAO,MAAM,YAAY,eAAmB,CAAC;AAiB7C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,EACE,QAAQ,EACR,MAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC,EACD,GAAG,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC9B;IACD,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B,CAqCA"}
package/build/index.mjs CHANGED
@@ -1,88 +1,3 @@
1
- if (process !== undefined)
2
- await import("@radically-straightforward/node");
3
- /**
4
- * Start a background job that runs every `interval`.
5
- *
6
- * This is different from `setInterval()` in the following ways:
7
- *
8
- * 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
9
- *
10
- * ```
11
- * setInterval()
12
- * | SLOW BACKGROUND JOB |
13
- * | INTERVAL | SLOW BACKGROUND JOB |
14
- * | INTERVAL | ...
15
- *
16
- * backgroundJob()
17
- * | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
18
- * ```
19
- *
20
- * 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
21
- *
22
- * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
23
- *
24
- * 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
25
- *
26
- * 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
27
- *
28
- * **Example**
29
- *
30
- * ```javascript
31
- * import * as utilities from "@radically-straightforward/utilities";
32
- *
33
- * const backgroundJob = utilities.backgroundJob(
34
- * { interval: 3 * 1000 },
35
- * async () => {
36
- * console.log("backgroundJob(): Running background job...");
37
- * await utilities.sleep(3 * 1000);
38
- * console.log("backgroundJob(): ...finished running background job.");
39
- * },
40
- * );
41
- * process.on("SIGTSTP", () => {
42
- * backgroundJob.run();
43
- * });
44
- * console.log(
45
- * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
46
- * );
47
- * ```
48
- */
49
- export function backgroundJob({ interval, intervalVariance = 0.1, }, job) {
50
- let state = "sleeping";
51
- let timeout = undefined;
52
- const scheduler = {
53
- run: async () => {
54
- switch (state) {
55
- case "sleeping":
56
- clearTimeout(timeout);
57
- state = "running";
58
- await job();
59
- if (state === "running" || state === "runningAndMarkedForRerun") {
60
- timeout = setTimeout(() => {
61
- scheduler.run();
62
- }, state === "runningAndMarkedForRerun"
63
- ? 0
64
- : interval + interval * intervalVariance * Math.random());
65
- state = "sleeping";
66
- }
67
- break;
68
- case "running":
69
- state = "runningAndMarkedForRerun";
70
- break;
71
- }
72
- },
73
- stop: () => {
74
- clearTimeout(timeout);
75
- state = "stopped";
76
- process?.off?.("gracefulTermination", gracefulTerminationEventListener);
77
- },
78
- };
79
- scheduler.run();
80
- const gracefulTerminationEventListener = () => {
81
- scheduler.stop();
82
- };
83
- process?.once?.("gracefulTermination", gracefulTerminationEventListener);
84
- return scheduler;
85
- }
86
1
  /**
87
2
  * A promisified version of `setTimeout()`. Bare-bones: It doesn’t even offer a way to `clearTimeout()`. Useful in JavaScript that may run in the browser—if you’re only targeting Node.js then you’re better served by [`timersPromises.setTimeout()`](https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options).
88
3
  */
@@ -161,10 +76,6 @@ export const emailRegExp = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
161
76
  * A regular expression that matches ISO dates, for example, `2024-04-01T14:19:48.162Z`.
162
77
  */
163
78
  export const ISODateRegExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
164
- /**
165
- * A regular expression that matches localized dates, for example, `2024-04-01 15:20`.
166
- */
167
- export const localizedDateRegExp = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/;
168
79
  /**
169
80
  * [Interning](<https://en.wikipedia.org/wiki/Interning_(computer_science)>) a value makes it unique across the program, which is useful for checking equality with `===` (reference equality), using it as a key in a `Map`, adding it to a `Set`, and so forth:
170
81
  *
@@ -309,4 +220,63 @@ intern.pool = {
309
220
  intern.finalizationRegistry = new FinalizationRegistry(({ type, key }) => {
310
221
  intern.pool[type].delete(key);
311
222
  });
223
+ /**
224
+ * > **Note:** This is a lower level utility. See `@radically-straightforward/node`’s and `@radically-straightforward/javascript`’s extensions to `backgroundJob()` that are better suited for their specific environments.
225
+ *
226
+ * Start a background job that runs every `interval`.
227
+ *
228
+ * `backgroundJob()` is different from `setInterval()` in the following ways:
229
+ *
230
+ * 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
231
+ *
232
+ * ```
233
+ * setInterval()
234
+ * | SLOW BACKGROUND JOB |
235
+ * | INTERVAL | SLOW BACKGROUND JOB |
236
+ * | INTERVAL | ...
237
+ *
238
+ * backgroundJob()
239
+ * | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
240
+ * ```
241
+ *
242
+ * 2. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of `0`).
243
+ *
244
+ * 3. You may use `backgroundJob.stop()` to stop the background job. If the background job is in the middle of running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
245
+ *
246
+ * 4. We introduce a random interval variance of 10% on top of the given `interval` to avoid many background jobs from starting at the same time and overloading the machine.
247
+ */
248
+ export function backgroundJob({ interval, onStop = () => { }, }, job) {
249
+ let state = "sleeping";
250
+ let timeout = setTimeout(() => { });
251
+ const scheduler = {
252
+ run: async () => {
253
+ switch (state) {
254
+ case "sleeping":
255
+ clearTimeout(timeout);
256
+ state = "running";
257
+ await job();
258
+ if (state === "running" || state === "runningAndMarkedForRerun") {
259
+ timeout = setTimeout(() => {
260
+ scheduler.run();
261
+ }, state ===
262
+ "runningAndMarkedForRerun"
263
+ ? 0
264
+ : interval * (1 + 0.1 * Math.random()));
265
+ state = "sleeping";
266
+ }
267
+ break;
268
+ case "running":
269
+ state = "runningAndMarkedForRerun";
270
+ break;
271
+ }
272
+ },
273
+ stop: async () => {
274
+ clearTimeout(timeout);
275
+ state = "stopped";
276
+ await onStop();
277
+ },
278
+ };
279
+ scheduler.run();
280
+ return scheduler;
281
+ }
312
282
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAAA,IAAI,OAAO,KAAK,SAAS;IAAE,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,UAAU,aAAa,CAC3B,EACE,QAAQ,EACR,gBAAgB,GAAG,GAAG,GAC0B,EAClD,GAA+B;IAE/B,IAAI,KAAK,GACP,UAAU,CAAC;IACb,IAAI,OAAO,GAAQ,SAAS,CAAC;IAC7B,MAAM,SAAS,GAAG;QAChB,GAAG,EAAE,KAAK,IAAI,EAAE;YACd,QAAQ,KAAK,EAAE,CAAC;gBACd,KAAK,UAAU;oBACb,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,KAAK,GAAG,SAAS,CAAC;oBAClB,MAAM,GAAG,EAAE,CAAC;oBACZ,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,0BAA0B,EAAE,CAAC;wBAChE,OAAO,GAAG,UAAU,CAClB,GAAG,EAAE;4BACH,SAAS,CAAC,GAAG,EAAE,CAAC;wBAClB,CAAC,EACA,KAAa,KAAK,0BAA0B;4BAC3C,CAAC,CAAC,CAAC;4BACH,CAAC,CAAC,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,IAAI,CAAC,MAAM,EAAE,CAC3D,CAAC;wBACF,KAAK,GAAG,UAAU,CAAC;oBACrB,CAAC;oBACD,MAAM;gBACR,KAAK,SAAS;oBACZ,KAAK,GAAG,0BAA0B,CAAC;oBACnC,MAAM;YACV,CAAC;QACH,CAAC;QACD,IAAI,EAAE,GAAG,EAAE;YACT,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,KAAK,GAAG,SAAS,CAAC;YAClB,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,EAAE,gCAAgC,CAAC,CAAC;QAC1E,CAAC;KACF,CAAC;IACF,SAAS,CAAC,GAAG,EAAE,CAAC;IAChB,MAAM,gCAAgC,GAAG,GAAG,EAAE;QAC5C,SAAS,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,CAAC,qBAAqB,EAAE,gCAAgC,CAAC,CAAC;IACzE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,QAAgB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,GAAG,YAAsB;IAC3C,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,wBAAyB,SAAQ,eAAe;IAC3D;QACE,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC;YACJ,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU;gBAC/B,MAAM,IAAI,MAAM,KAAK,CAAC;gBACtB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;gBAC3B,KAAK,MAAM,IAAI,IAAI,KAAK;oBACtB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;wBACpB,IAAI,CAAC;4BACH,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;wBACvC,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;wBAC1B,CAAC;YACP,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC;QACxB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,OAAO,CACL,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAW,0CAA0C,CAAC;AAE9E;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GACxB,+CAA+C,CAAC;AAElD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAW,iCAAiC,CAAC;AAoB7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,MAAM,UAAU,MAAM,CAEpB,KAAW;IACX,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC/B,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAC3C,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC,CAAC,EAAE,CAAC;IACX,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QACvD,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC;QAC1C,IACE,WAAW,KAAK,SAAS;YACzB,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM;YAE/C,SAAS;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAE,KAAa,CAAC,GAAG,CAAC,KAAM,WAAmB,CAAC,GAAG,CAAC,CAAC;YACxE,OAAO,WAAkB,CAAC;IAC9B,CAAC;IACD,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;QAC3C,IACE,CAAC,CACC,OAAO,UAAU,KAAK,QAAQ;YAC9B,OAAO,UAAU,KAAK,QAAQ;YAC9B,OAAO,UAAU,KAAK,QAAQ;YAC9B,OAAO,UAAU,KAAK,SAAS;YAC/B,OAAO,UAAU,KAAK,QAAQ;YAC9B,UAAU,KAAK,SAAS;YACxB,UAAU,KAAK,IAAI;YAClB,UAAkB,CAAC,YAAY,CAAC,KAAK,IAAI,CAC3C;YAED,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACN,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACpB,KAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,KAAY,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,oBAAoB,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3D,OAAO,KAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,CAAC,IAAI,GAAG;IACZ,KAAK,EAAE,IAAI,GAAG,EAA+C;IAC7D,MAAM,EAAE,IAAI,GAAG,EAGZ;CACJ,CAAC;AAEF,MAAM,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAGnD,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;IACnB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"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"}
@@ -2,26 +2,6 @@ import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import * as utilities from "@radically-straightforward/utilities";
4
4
  import { intern as $ } from "@radically-straightforward/utilities";
5
- test("backgroundJob()", {
6
- skip: process.stdin.isTTY
7
- ? false
8
- : "Run interactive test with ‘node ./build/index.test.mjs’.",
9
- }, async () => {
10
- for (let iteration = 0; iteration < 1000; iteration++) {
11
- const backgroundJob = utilities.backgroundJob({ interval: 3 * 1000 }, () => { });
12
- backgroundJob.stop();
13
- // If background jobs leak ‘process.once("gracefulTermination")’ event listeners, then we get a warning in the console.
14
- }
15
- const backgroundJob = utilities.backgroundJob({ interval: 3 * 1000 }, async () => {
16
- console.log("backgroundJob(): Running background job...");
17
- await utilities.sleep(3 * 1000);
18
- console.log("backgroundJob(): ...finished running background job.");
19
- });
20
- process.on("SIGTSTP", () => {
21
- backgroundJob.run();
22
- });
23
- console.log("backgroundJob(): Press ⌃Z to force background job to run and ⌃C to gracefully terminate...");
24
- });
25
5
  test("sleep()", async () => {
26
6
  const before = Date.now();
27
7
  await utilities.sleep(1000);
@@ -78,10 +58,6 @@ test("ISODateRegExp", () => {
78
58
  assert.match("2024-04-01T14:19:48.162Z", utilities.ISODateRegExp);
79
59
  assert.doesNotMatch("2024-04-01 15:20", utilities.ISODateRegExp);
80
60
  });
81
- test("localizedDateRegExp", () => {
82
- assert.match("2024-04-01 15:20", utilities.localizedDateRegExp);
83
- assert.doesNotMatch("2024-04-01T14:19:48.162Z", utilities.localizedDateRegExp);
84
- });
85
61
  test("intern()", () => {
86
62
  // @ts-expect-error
87
63
  assert(([1] === [1]) === false);
@@ -125,20 +101,23 @@ test("intern()", () => {
125
101
  // @ts-expect-error
126
102
  $([1])[0] = 2;
127
103
  });
128
- {
129
- const iterations = 1000;
130
- console.time("intern()");
131
- const objects = [];
132
- for (let iteration = 0; iteration < iterations; iteration++) {
133
- const entries = [];
134
- for (let key = 0; key < Math.floor(Math.random() * 15); key++) {
135
- entries.push([String(key + Math.floor(Math.random() * 15)), true]);
136
- }
137
- objects.push($(Object.fromEntries(entries)));
138
- objects.push($(entries.flat()));
139
- }
140
- // console.log($.pool.record.size);
141
- console.timeEnd("intern()");
142
- }
104
+ });
105
+ test("backgroundJob()", {
106
+ skip: process.stdin.isTTY
107
+ ? false
108
+ : "Run interactive test with ‘node ./build/index.test.mjs’.",
109
+ }, async () => {
110
+ const backgroundJob = utilities.backgroundJob({ interval: 3 * 1000 }, async () => {
111
+ console.log("backgroundJob(): Running background job...");
112
+ await utilities.sleep(3 * 1000);
113
+ console.log("backgroundJob(): ...finished running background job.");
114
+ });
115
+ process.on("SIGTSTP", () => {
116
+ backgroundJob.run();
117
+ });
118
+ process.on("SIGINT", () => {
119
+ backgroundJob.stop();
120
+ });
121
+ console.log("backgroundJob(): Press ⌃Z to ‘run()’ and ⌃C to ‘stop()’...");
143
122
  });
144
123
  //# sourceMappingURL=index.test.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.mjs","sourceRoot":"","sources":["../source/index.test.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.test.mjs","sourceRoot":"","sources":["../source/index.test.mts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radically-straightforward/utilities",
3
- "version": "1.2.2",
3
+ "version": "2.0.0",
4
4
  "description": "🛠️ Utilities for Node.js and the browser",
5
5
  "keywords": [
6
6
  "node",
@@ -27,9 +27,6 @@
27
27
  "prepare": "tsc && documentation",
28
28
  "test": "npm run prepare && node --test && prettier --check \"./README.md\" --check \"./CHANGELOG.md\" --check \"./package.json\" --check \"./tsconfig.json\" --check \"./source/**/*.mts\""
29
29
  },
30
- "dependencies": {
31
- "@radically-straightforward/node": "^3.0.0"
32
- },
33
30
  "devDependencies": {
34
31
  "@radically-straightforward/documentation": "^1.0.1",
35
32
  "@radically-straightforward/tsconfig": "^1.0.0",
package/source/index.mts CHANGED
@@ -1,99 +1,3 @@
1
- if (process !== undefined) await import("@radically-straightforward/node");
2
-
3
- /**
4
- * Start a background job that runs every `interval`.
5
- *
6
- * This is different from `setInterval()` in the following ways:
7
- *
8
- * 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
9
- *
10
- * ```
11
- * setInterval()
12
- * | SLOW BACKGROUND JOB |
13
- * | INTERVAL | SLOW BACKGROUND JOB |
14
- * | INTERVAL | ...
15
- *
16
- * backgroundJob()
17
- * | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
18
- * ```
19
- *
20
- * 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
21
- *
22
- * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
23
- *
24
- * 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
25
- *
26
- * 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
27
- *
28
- * **Example**
29
- *
30
- * ```javascript
31
- * import * as utilities from "@radically-straightforward/utilities";
32
- *
33
- * const backgroundJob = utilities.backgroundJob(
34
- * { interval: 3 * 1000 },
35
- * async () => {
36
- * console.log("backgroundJob(): Running background job...");
37
- * await utilities.sleep(3 * 1000);
38
- * console.log("backgroundJob(): ...finished running background job.");
39
- * },
40
- * );
41
- * process.on("SIGTSTP", () => {
42
- * backgroundJob.run();
43
- * });
44
- * console.log(
45
- * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
46
- * );
47
- * ```
48
- */
49
- export function backgroundJob(
50
- {
51
- interval,
52
- intervalVariance = 0.1,
53
- }: { interval: number; intervalVariance?: number },
54
- job: () => void | Promise<void>,
55
- ): { run: () => void; stop: () => void } {
56
- let state: "sleeping" | "running" | "runningAndMarkedForRerun" | "stopped" =
57
- "sleeping";
58
- let timeout: any = undefined;
59
- const scheduler = {
60
- run: async () => {
61
- switch (state) {
62
- case "sleeping":
63
- clearTimeout(timeout);
64
- state = "running";
65
- await job();
66
- if (state === "running" || state === "runningAndMarkedForRerun") {
67
- timeout = setTimeout(
68
- () => {
69
- scheduler.run();
70
- },
71
- (state as any) === "runningAndMarkedForRerun"
72
- ? 0
73
- : interval + interval * intervalVariance * Math.random(),
74
- );
75
- state = "sleeping";
76
- }
77
- break;
78
- case "running":
79
- state = "runningAndMarkedForRerun";
80
- break;
81
- }
82
- },
83
- stop: () => {
84
- clearTimeout(timeout);
85
- state = "stopped";
86
- process?.off?.("gracefulTermination", gracefulTerminationEventListener);
87
- },
88
- };
89
- scheduler.run();
90
- const gracefulTerminationEventListener = () => {
91
- scheduler.stop();
92
- };
93
- process?.once?.("gracefulTermination", gracefulTerminationEventListener);
94
- return scheduler;
95
- }
96
-
97
1
  /**
98
2
  * A promisified version of `setTimeout()`. Bare-bones: It doesn’t even offer a way to `clearTimeout()`. Useful in JavaScript that may run in the browser—if you’re only targeting Node.js then you’re better served by [`timersPromises.setTimeout()`](https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options).
99
3
  */
@@ -182,11 +86,6 @@ export const emailRegExp: RegExp = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
182
86
  export const ISODateRegExp: RegExp =
183
87
  /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
184
88
 
185
- /**
186
- * A regular expression that matches localized dates, for example, `2024-04-01 15:20`.
187
- */
188
- export const localizedDateRegExp: RegExp = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/;
189
-
190
89
  /**
191
90
  * Utility type for `intern()`.
192
91
  */
@@ -368,3 +267,79 @@ intern.finalizationRegistry = new FinalizationRegistry<{
368
267
  }>(({ type, key }) => {
369
268
  intern.pool[type].delete(key);
370
269
  });
270
+
271
+ /**
272
+ * > **Note:** This is a lower level utility. See `@radically-straightforward/node`’s and `@radically-straightforward/javascript`’s extensions to `backgroundJob()` that are better suited for their specific environments.
273
+ *
274
+ * Start a background job that runs every `interval`.
275
+ *
276
+ * `backgroundJob()` is different from `setInterval()` in the following ways:
277
+ *
278
+ * 1. The interval counts **between** jobs, so slow background jobs don’t get called concurrently:
279
+ *
280
+ * ```
281
+ * setInterval()
282
+ * | SLOW BACKGROUND JOB |
283
+ * | INTERVAL | SLOW BACKGROUND JOB |
284
+ * | INTERVAL | ...
285
+ *
286
+ * backgroundJob()
287
+ * | SLOW BACKGROUND JOB | INTERVAL | SLOW BACKGROUND JOB | INTERVAL | ...
288
+ * ```
289
+ *
290
+ * 2. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of `0`).
291
+ *
292
+ * 3. You may use `backgroundJob.stop()` to stop the background job. If the background job is in the middle of running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
293
+ *
294
+ * 4. We introduce a random interval variance of 10% on top of the given `interval` to avoid many background jobs from starting at the same time and overloading the machine.
295
+ */
296
+ export function backgroundJob(
297
+ {
298
+ interval,
299
+ onStop = () => {},
300
+ }: {
301
+ interval: number;
302
+ onStop?: () => void | Promise<void>;
303
+ },
304
+ job: () => void | Promise<void>,
305
+ ): {
306
+ run: () => Promise<void>;
307
+ stop: () => Promise<void>;
308
+ } {
309
+ let state: "sleeping" | "running" | "runningAndMarkedForRerun" | "stopped" =
310
+ "sleeping";
311
+ let timeout = setTimeout(() => {});
312
+ const scheduler = {
313
+ run: async () => {
314
+ switch (state) {
315
+ case "sleeping":
316
+ clearTimeout(timeout);
317
+ state = "running";
318
+ await job();
319
+ if (state === "running" || state === "runningAndMarkedForRerun") {
320
+ timeout = setTimeout(
321
+ () => {
322
+ scheduler.run();
323
+ },
324
+ (state as "running" | "runningAndMarkedForRerun") ===
325
+ "runningAndMarkedForRerun"
326
+ ? 0
327
+ : interval * (1 + 0.1 * Math.random()),
328
+ );
329
+ state = "sleeping";
330
+ }
331
+ break;
332
+ case "running":
333
+ state = "runningAndMarkedForRerun";
334
+ break;
335
+ }
336
+ },
337
+ stop: async () => {
338
+ clearTimeout(timeout);
339
+ state = "stopped";
340
+ await onStop();
341
+ },
342
+ };
343
+ scheduler.run();
344
+ return scheduler;
345
+ }
@@ -3,40 +3,6 @@ import assert from "node:assert/strict";
3
3
  import * as utilities from "@radically-straightforward/utilities";
4
4
  import { intern as $ } from "@radically-straightforward/utilities";
5
5
 
6
- test(
7
- "backgroundJob()",
8
- {
9
- skip: process.stdin.isTTY
10
- ? false
11
- : "Run interactive test with ‘node ./build/index.test.mjs’.",
12
- },
13
- async () => {
14
- for (let iteration = 0; iteration < 1000; iteration++) {
15
- const backgroundJob = utilities.backgroundJob(
16
- { interval: 3 * 1000 },
17
- () => {},
18
- );
19
- backgroundJob.stop();
20
- // If background jobs leak ‘process.once("gracefulTermination")’ event listeners, then we get a warning in the console.
21
- }
22
-
23
- const backgroundJob = utilities.backgroundJob(
24
- { interval: 3 * 1000 },
25
- async () => {
26
- console.log("backgroundJob(): Running background job...");
27
- await utilities.sleep(3 * 1000);
28
- console.log("backgroundJob(): ...finished running background job.");
29
- },
30
- );
31
- process.on("SIGTSTP", () => {
32
- backgroundJob.run();
33
- });
34
- console.log(
35
- "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to gracefully terminate...",
36
- );
37
- },
38
- );
39
-
40
6
  test("sleep()", async () => {
41
7
  const before = Date.now();
42
8
  await utilities.sleep(1000);
@@ -105,14 +71,6 @@ test("ISODateRegExp", () => {
105
71
  assert.doesNotMatch("2024-04-01 15:20", utilities.ISODateRegExp);
106
72
  });
107
73
 
108
- test("localizedDateRegExp", () => {
109
- assert.match("2024-04-01 15:20", utilities.localizedDateRegExp);
110
- assert.doesNotMatch(
111
- "2024-04-01T14:19:48.162Z",
112
- utilities.localizedDateRegExp,
113
- );
114
- });
115
-
116
74
  test("intern()", () => {
117
75
  // @ts-expect-error
118
76
  assert(([1] === [1]) === false);
@@ -163,20 +121,30 @@ test("intern()", () => {
163
121
  // @ts-expect-error
164
122
  $([1])[0] = 2;
165
123
  });
124
+ });
166
125
 
126
+ test(
127
+ "backgroundJob()",
167
128
  {
168
- const iterations = 1000;
169
- console.time("intern()");
170
- const objects = [];
171
- for (let iteration = 0; iteration < iterations; iteration++) {
172
- const entries = [];
173
- for (let key = 0; key < Math.floor(Math.random() * 15); key++) {
174
- entries.push([String(key + Math.floor(Math.random() * 15)), true]);
175
- }
176
- objects.push($(Object.fromEntries(entries)));
177
- objects.push($(entries.flat()));
178
- }
179
- // console.log($.pool.record.size);
180
- console.timeEnd("intern()");
181
- }
182
- });
129
+ skip: process.stdin.isTTY
130
+ ? false
131
+ : "Run interactive test with ‘node ./build/index.test.mjs’.",
132
+ },
133
+ async () => {
134
+ const backgroundJob = utilities.backgroundJob(
135
+ { interval: 3 * 1000 },
136
+ async () => {
137
+ console.log("backgroundJob(): Running background job...");
138
+ await utilities.sleep(3 * 1000);
139
+ console.log("backgroundJob(): ...finished running background job.");
140
+ },
141
+ );
142
+ process.on("SIGTSTP", () => {
143
+ backgroundJob.run();
144
+ });
145
+ process.on("SIGINT", () => {
146
+ backgroundJob.stop();
147
+ });
148
+ console.log("backgroundJob(): Press ⌃Z to ‘run()’ and ⌃C to ‘stop()’...");
149
+ },
150
+ );