@stonyx/cron 0.2.1-alpha.17 → 0.2.1-alpha.19

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/dist/service.d.ts CHANGED
@@ -28,6 +28,7 @@ interface ListOptions {
28
28
  }
29
29
  type OnJobDueCallback = (job: Job) => Promise<JobDueResult | void> | JobDueResult | void;
30
30
  export default class CronService {
31
+ #private;
31
32
  jobs: Map<string, Job>;
32
33
  heap: MinHeap<HeapEntry>;
33
34
  timer: ReturnType<typeof setTimeout> | null;
@@ -91,10 +92,14 @@ export default class CronService {
91
92
  * lock is what wedged every subsequent `locked()` call (add/update/remove)
92
93
  * when a callback never settled.
93
94
  *
94
- * `alreadyClaimed` is passed by `onTimer`, which performs the batch claim
95
- * (findDueJobs + markRunning) for all due jobs under a single lock.
95
+ * `onTimer` performs the batch claim (findDueJobs + markRunning) for all due
96
+ * jobs under a single lock, then enters at phase 2 via `#executeClaimed`.
97
+ * That entry point is a `#private` method rather than a parameter on this
98
+ * one: as a published `alreadyClaimed` boolean it was a supported way for a
99
+ * consumer to skip phase 1 entirely, which defeats the claim guard AC4 asks
100
+ * for and allows concurrent `onJobDue` invocations for the same job.
96
101
  */
97
- executeJob(job: Job, alreadyClaimed?: boolean): Promise<ExecuteResult>;
102
+ executeJob(job: Job): Promise<ExecuteResult>;
98
103
  /**
99
104
  * Phase 1 - claim. Must be called while holding the lock.
100
105
  *
package/dist/service.js CHANGED
@@ -210,7 +210,7 @@ export default class CronService {
210
210
  // cannot poison the lock chain.
211
211
  for (const job of dueJobs) {
212
212
  try {
213
- await this.executeJob(job, true);
213
+ await this.#executeClaimed(job);
214
214
  }
215
215
  catch (err) {
216
216
  // One job's unexpected throw must not abort the batch. Every job in
@@ -262,16 +262,28 @@ export default class CronService {
262
262
  * lock is what wedged every subsequent `locked()` call (add/update/remove)
263
263
  * when a callback never settled.
264
264
  *
265
- * `alreadyClaimed` is passed by `onTimer`, which performs the batch claim
266
- * (findDueJobs + markRunning) for all due jobs under a single lock.
265
+ * `onTimer` performs the batch claim (findDueJobs + markRunning) for all due
266
+ * jobs under a single lock, then enters at phase 2 via `#executeClaimed`.
267
+ * That entry point is a `#private` method rather than a parameter on this
268
+ * one: as a published `alreadyClaimed` boolean it was a supported way for a
269
+ * consumer to skip phase 1 entirely, which defeats the claim guard AC4 asks
270
+ * for and allows concurrent `onJobDue` invocations for the same job.
267
271
  */
268
- async executeJob(job, alreadyClaimed = false) {
272
+ async executeJob(job) {
269
273
  // -- Phase 1: claim (locked) --
270
- if (!alreadyClaimed) {
271
- const refusal = await locked(() => this.claimJob(job));
272
- if (refusal)
273
- return { status: 'skipped', reason: refusal };
274
- }
274
+ const refusal = await locked(() => this.claimJob(job));
275
+ if (refusal)
276
+ return { status: 'skipped', reason: refusal };
277
+ return this.#executeClaimed(job);
278
+ }
279
+ /**
280
+ * Phases 2 and 3 for a job that has already been claimed - either by
281
+ * `executeJob` above or by `onTimer`'s batch claim.
282
+ *
283
+ * Private: reaching this without a claim would run the consumer callback for
284
+ * a job nobody owns.
285
+ */
286
+ async #executeClaimed(job) {
275
287
  // Membership re-check. The claim and the invoke are no longer in the same
276
288
  // critical section, and sibling callbacks run unlocked, so a `remove()` can
277
289
  // land in between AND RESOLVE - it used to deadlock. A resolved `remove()`
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "keywords": [
4
4
  "stonyx-module"
5
5
  ],
6
- "version": "0.2.1-alpha.17",
6
+ "version": "0.2.1-alpha.19",
7
7
  "description": "Cron/job scheduler for Stonyx framework",
8
8
  "main": "dist/main.js",
9
9
  "types": "dist/main.d.ts",