anbaric-state-machine 1.23.2 → 1.24.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/dist/index.d.ts CHANGED
@@ -11,6 +11,10 @@ export * from "./scheduling/InMemoryQueue.js";
11
11
  export * from "./scheduling/PullConsumer.js";
12
12
  export * from "./scheduling/ConsumerFactory.js";
13
13
  export * from "./scheduling/QueueFactory.js";
14
+ export * from "./scheduling/Schedule.js";
15
+ export * from "./scheduling/JobRunScheduler.js";
16
+ export * from "./scheduling/InMemoryJobRunSchedulePersistence.js";
17
+ export * from "./scheduling/JobRunSchedulePersistenceFactory.js";
14
18
  export * from "./sessions/InMemorySessionResolver.js";
15
19
  export * from "./sessions/SessionResolverFactory.js";
16
20
  export * from "./sessions/sessionCookie.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qCAAqC,CAAC;AACpD,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qCAAqC,CAAC;AACpD,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,mDAAmD,CAAC;AAClE,cAAc,kDAAkD,CAAC;AACjE,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC"}
package/dist/index.js CHANGED
@@ -11,6 +11,10 @@ export * from "./scheduling/InMemoryQueue.js";
11
11
  export * from "./scheduling/PullConsumer.js";
12
12
  export * from "./scheduling/ConsumerFactory.js";
13
13
  export * from "./scheduling/QueueFactory.js";
14
+ export * from "./scheduling/Schedule.js";
15
+ export * from "./scheduling/JobRunScheduler.js";
16
+ export * from "./scheduling/InMemoryJobRunSchedulePersistence.js";
17
+ export * from "./scheduling/JobRunSchedulePersistenceFactory.js";
14
18
  export * from "./sessions/InMemorySessionResolver.js";
15
19
  export * from "./sessions/SessionResolverFactory.js";
16
20
  export * from "./sessions/sessionCookie.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qCAAqC,CAAC;AACpD,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qCAAqC,CAAC;AACpD,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,mDAAmD,CAAC;AAClE,cAAc,kDAAkD,CAAC;AACjE,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { JobRunSchedulePersistence, ScheduledRun } from "anbaric-tsapi";
2
+ declare class InMemoryJobRunSchedulePersistence implements JobRunSchedulePersistence {
3
+ private runs;
4
+ highWaterMark(appId: string, workflowId: string): Promise<Date | undefined>;
5
+ plan(runs: Array<ScheduledRun>): Promise<void>;
6
+ claimDue(at: Date): Promise<Array<ScheduledRun>>;
7
+ private alreadyPlanned;
8
+ }
9
+ export { InMemoryJobRunSchedulePersistence };
10
+ //# sourceMappingURL=InMemoryJobRunSchedulePersistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryJobRunSchedulePersistence.d.ts","sourceRoot":"","sources":["../../src/scheduling/InMemoryJobRunSchedulePersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,yBAAyB,EAAE,YAAY,EAAC,MAAM,eAAe,CAAC;AAItE,cAAM,iCAAkC,YAAW,yBAAyB;IAExE,OAAO,CAAC,IAAI,CAA0B;IAEhC,aAAa,CAAC,KAAK,EAAG,MAAM,EAAE,UAAU,EAAG,MAAM,GAAI,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAKnF;IAEK,IAAI,CAAC,IAAI,EAAG,KAAK,CAAC,YAAY,CAAC,GAAI,OAAO,CAAC,IAAI,CAAC,CAKrD;IAEK,QAAQ,CAAC,EAAE,EAAG,IAAI,GAAI,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAIvD;IAED,OAAO,CAAC,cAAc;CAOzB;AAED,OAAO,EAAE,iCAAiC,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ class InMemoryJobRunSchedulePersistence {
2
+ runs = [];
3
+ async highWaterMark(appId, workflowId) {
4
+ const times = this.runs
5
+ .filter(run => run.appId === appId && run.workflowId === workflowId)
6
+ .map(run => run.runAt.getTime());
7
+ return times.length === 0 ? undefined : new Date(Math.max(...times));
8
+ }
9
+ async plan(runs) {
10
+ for (const run of runs) {
11
+ if (this.alreadyPlanned(run))
12
+ continue;
13
+ this.runs.push({ ...run, claimed: false });
14
+ }
15
+ }
16
+ async claimDue(at) {
17
+ const due = this.runs.filter(run => !run.claimed && run.runAt.getTime() <= at.getTime());
18
+ for (const run of due)
19
+ run.claimed = true;
20
+ return due.map(({ appId, workflowId, runAt }) => ({ appId, workflowId, runAt }));
21
+ }
22
+ alreadyPlanned(run) {
23
+ return this.runs.some(planned => planned.appId === run.appId
24
+ && planned.workflowId === run.workflowId
25
+ && planned.runAt.getTime() === run.runAt.getTime());
26
+ }
27
+ }
28
+ export { InMemoryJobRunSchedulePersistence };
29
+ //# sourceMappingURL=InMemoryJobRunSchedulePersistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryJobRunSchedulePersistence.js","sourceRoot":"","sources":["../../src/scheduling/InMemoryJobRunSchedulePersistence.ts"],"names":[],"mappings":"AAIA,MAAM,iCAAiC;IAE3B,IAAI,GAAuB,EAAE,CAAC;IAEtC,KAAK,CAAC,aAAa,CAAC,KAAc,EAAE,UAAmB;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI;aAClB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,UAAU,KAAK,UAAU,CAAC;aACnE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAA0B;QACjC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;gBAAE,SAAS;YACvC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,EAAS;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACzF,KAAK,MAAM,GAAG,IAAI,GAAG;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1C,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC;IAEO,cAAc,CAAC,GAAkB;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAC5B,OAAO,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK;eACxB,OAAO,CAAC,UAAU,KAAK,GAAG,CAAC,UAAU;eACrC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;CAEJ;AAED,OAAO,EAAE,iCAAiC,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { JobRunSchedulePersistence } from "anbaric-tsapi";
2
+ declare const JobRunSchedulePersistenceFactory: {
3
+ instance(): JobRunSchedulePersistence;
4
+ };
5
+ export { JobRunSchedulePersistenceFactory };
6
+ //# sourceMappingURL=JobRunSchedulePersistenceFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobRunSchedulePersistenceFactory.d.ts","sourceRoot":"","sources":["../../src/scheduling/JobRunSchedulePersistenceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,yBAAyB,EAAC,MAAM,eAAe,CAAC;AAIxD,QAAA,MAAM,gCAAgC;IAClC,QAAQ,IAAK,yBAAyB;CASzC,CAAA;AAED,OAAO,EAAE,gCAAgC,EAAE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { CloudJobRunSchedulePersistence } from "anbaric-impl-cloud";
2
+ import { InMemoryJobRunSchedulePersistence } from "./InMemoryJobRunSchedulePersistence.js";
3
+ const JobRunSchedulePersistenceFactory = {
4
+ instance() {
5
+ switch (process.env.ANBARIC_JOB_RUN_SCHEDULE_PERSISTENCE_TYPE) {
6
+ case "cloud":
7
+ return new CloudJobRunSchedulePersistence();
8
+ case "memory":
9
+ default:
10
+ return new InMemoryJobRunSchedulePersistence();
11
+ }
12
+ }
13
+ };
14
+ export { JobRunSchedulePersistenceFactory };
15
+ //# sourceMappingURL=JobRunSchedulePersistenceFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobRunSchedulePersistenceFactory.js","sourceRoot":"","sources":["../../src/scheduling/JobRunSchedulePersistenceFactory.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAC,iCAAiC,EAAC,MAAM,wCAAwC,CAAC;AAEzF,MAAM,gCAAgC,GAAG;IACrC,QAAQ;QACJ,QAAQ,OAAO,CAAC,GAAG,CAAC,yCAAyC,EAAE,CAAC;YAC5D,KAAK,OAAO;gBACR,OAAO,IAAI,8BAA8B,EAAE,CAAC;YAChD,KAAK,QAAQ,CAAC;YACd;gBACI,OAAO,IAAI,iCAAiC,EAAE,CAAC;QACvD,CAAC;IACL,CAAC;CACJ,CAAA;AAED,OAAO,EAAE,gCAAgC,EAAE,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { JobRunSchedulePersistence } from "anbaric-tsapi";
2
+ import { StateMachine } from "../StateMachine.js";
3
+ import { Schedule } from "./Schedule.js";
4
+ declare class JobRunScheduler {
5
+ private persistence;
6
+ private static singleton?;
7
+ private machines;
8
+ private ticker?;
9
+ private ticking;
10
+ constructor(persistence?: JobRunSchedulePersistence);
11
+ static instance(): JobRunScheduler;
12
+ schedule(machine: StateMachine, at: Schedule, lookaheadMs?: number, randomRunOffsetMs?: [number, number]): void;
13
+ tick(now?: Date): Promise<void>;
14
+ cleanUp(): Promise<void>;
15
+ private start;
16
+ private tickOnce;
17
+ private planAhead;
18
+ private startDue;
19
+ private withOffset;
20
+ private propertiesFor;
21
+ private key;
22
+ }
23
+ export { JobRunScheduler };
24
+ //# sourceMappingURL=JobRunScheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobRunScheduler.d.ts","sourceRoot":"","sources":["../../src/scheduling/JobRunScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,yBAAyB,EAAe,MAAM,eAAe,CAAC;AACtE,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAuBvC,cAAM,eAAe;IAQL,OAAO,CAAC,WAAW;IAN/B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAmB;IAE5C,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,MAAM,CAAC,CAAkC;IACjD,OAAO,CAAC,OAAO,CAAS;IAExB,YAAoB,WAAW,GAAG,yBAAuE,EAAI;IAE7G,MAAM,CAAC,QAAQ,IAAK,eAAe,CAGlC;IAED,QAAQ,CAAC,OAAO,EAAG,YAAY,EAAE,EAAE,EAAG,QAAQ,EAAE,WAAW,GAAG,MAA6B,EAAE,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAyB,GAAI,IAAI,CAIhK;IAGK,IAAI,CAAC,GAAG,GAAG,IAAiB,GAAI,OAAO,CAAC,IAAI,CAAC,CAGlD;IAEK,OAAO,IAAK,OAAO,CAAC,IAAI,CAAC,CAI9B;IAED,OAAO,CAAC,KAAK;YAOC,QAAQ;YAYR,SAAS;YAkBT,QAAQ;IAWtB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,GAAG;CAId;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,106 @@
1
+ import { JobRunSchedulePersistenceFactory } from "./JobRunSchedulePersistenceFactory.js";
2
+ const TICK_INTERVAL_MS = 1000;
3
+ const DEFAULT_LOOKAHEAD_MS = 1000 * 60 * 60 * 24;
4
+ const DEFAULT_RUN_OFFSET_MS = [0, 1000 * 60 * 2];
5
+ /* Starts jobs on a timetable. Runs are planned ahead of time and stored, so
6
+ the plan survives a restart and a machine that was down does not silently
7
+ skip its runs; each tick plans further ahead and starts whatever has come
8
+ due. Planning and starting are separate on purpose - a run is a record long
9
+ before it is a job.
10
+
11
+ How safely two schedulers can share a plan is the persistence's business:
12
+ the in-memory one claims within a single process, while the platform-backed
13
+ one claims atomically, so a deployed app can run several instances and each
14
+ due run still starts exactly once. */
15
+ class JobRunScheduler {
16
+ persistence;
17
+ static singleton;
18
+ machines = new Map();
19
+ ticker;
20
+ ticking = false;
21
+ constructor(persistence = JobRunSchedulePersistenceFactory.instance()) {
22
+ this.persistence = persistence;
23
+ }
24
+ static instance() {
25
+ if (!JobRunScheduler.singleton)
26
+ JobRunScheduler.singleton = new JobRunScheduler();
27
+ return JobRunScheduler.singleton;
28
+ }
29
+ schedule(machine, at, lookaheadMs = DEFAULT_LOOKAHEAD_MS, randomRunOffsetMs = DEFAULT_RUN_OFFSET_MS) {
30
+ this.machines.set(this.key(machine.getAppId(), machine.workflowId), { machine, schedule: at, lookaheadMs, randomRunOffsetMs });
31
+ this.start();
32
+ }
33
+ // Plans and starts everything owed as at `now`, without waiting for a tick.
34
+ async tick(now = new Date()) {
35
+ for (const scheduled of this.machines.values())
36
+ await this.planAhead(scheduled, now);
37
+ await this.startDue(now);
38
+ }
39
+ async cleanUp() {
40
+ if (this.ticker)
41
+ clearInterval(this.ticker);
42
+ this.ticker = undefined;
43
+ this.machines.clear();
44
+ }
45
+ start() {
46
+ if (this.ticker)
47
+ return;
48
+ this.ticker = setInterval(() => void this.tickOnce(), TICK_INTERVAL_MS);
49
+ // Scheduling alone should not hold a process open.
50
+ this.ticker.unref?.();
51
+ }
52
+ async tickOnce() {
53
+ if (this.ticking)
54
+ return;
55
+ this.ticking = true;
56
+ try {
57
+ await this.tick();
58
+ }
59
+ catch {
60
+ // A failing tick must not kill the timer; the next one retries.
61
+ }
62
+ finally {
63
+ this.ticking = false;
64
+ }
65
+ }
66
+ async planAhead(scheduled, now) {
67
+ const appId = scheduled.machine.getAppId();
68
+ const workflowId = scheduled.machine.workflowId;
69
+ const planned = await this.persistence.highWaterMark(appId, workflowId);
70
+ const from = planned && planned.getTime() > now.getTime() ? planned : now;
71
+ const to = new Date(now.getTime() + scheduled.lookaheadMs);
72
+ if (to.getTime() <= from.getTime())
73
+ return;
74
+ const runs = scheduled.schedule.getRuns(from, to).map(runAt => ({
75
+ appId,
76
+ workflowId,
77
+ runAt: this.withOffset(runAt, scheduled.randomRunOffsetMs),
78
+ }));
79
+ if (runs.length > 0)
80
+ await this.persistence.plan(runs);
81
+ }
82
+ async startDue(now) {
83
+ for (const run of await this.persistence.claimDue(now)) {
84
+ const scheduled = this.machines.get(this.key(run.appId, run.workflowId));
85
+ if (!scheduled)
86
+ continue;
87
+ await scheduled.machine.startJob(this.propertiesFor(run));
88
+ }
89
+ }
90
+ // Spreads runs that would otherwise all fire on the same second. Applied
91
+ // when the run is planned, not when it starts, so the time that was stored
92
+ // is the time it actually runs.
93
+ withOffset(runAt, [lowest, highest]) {
94
+ if (highest <= lowest)
95
+ return runAt;
96
+ return new Date(runAt.getTime() + Math.round(Math.random() * (highest - lowest)) + lowest);
97
+ }
98
+ propertiesFor(run) {
99
+ return new Map([["scheduledFor", run.runAt.toISOString()]]);
100
+ }
101
+ key(appId, workflowId) {
102
+ return JSON.stringify([appId, workflowId]);
103
+ }
104
+ }
105
+ export { JobRunScheduler };
106
+ //# sourceMappingURL=JobRunScheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobRunScheduler.js","sourceRoot":"","sources":["../../src/scheduling/JobRunScheduler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,gCAAgC,EAAC,MAAM,uCAAuC,CAAC;AAGvF,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACjD,MAAM,qBAAqB,GAAsB,CAAC,CAAC,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AASpE;;;;;;;;;wCASwC;AACxC,MAAM,eAAe;IAQG,WAAW;IANvB,MAAM,CAAC,SAAS,CAAoB;IAEpC,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAC/C,MAAM,CAAmC;IACzC,OAAO,GAAG,KAAK,CAAC;IAExB,YAAoB,WAAW,GAA+B,gCAAgC,CAAC,QAAQ,EAAE;2BAArF,WAAW;IAA6E,CAAC;IAE7G,MAAM,CAAC,QAAQ;QACX,IAAI,CAAC,eAAe,CAAC,SAAS;YAAE,eAAe,CAAC,SAAS,GAAG,IAAI,eAAe,EAAE,CAAC;QAClF,OAAO,eAAe,CAAC,SAAS,CAAC;IACrC,CAAC;IAED,QAAQ,CAAC,OAAsB,EAAE,EAAa,EAAE,WAAW,GAAY,oBAAoB,EAAE,iBAAiB,GAAsB,qBAAqB;QACrJ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,EAC9D,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAED,4EAA4E;IAC5E,KAAK,CAAC,IAAI,CAAC,GAAG,GAAU,IAAI,IAAI,EAAE;QAC9B,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;YAAE,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACrF,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,OAAO;QACT,IAAI,IAAI,CAAC,MAAM;YAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAEO,KAAK;QACT,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,EAAE,gBAAgB,CAAC,CAAC;QACxE,mDAAmD;QACnD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,QAAQ;QAClB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACL,gEAAgE;QACpE,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACzB,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,SAA4B,EAAE,GAAU;QAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC;QAEhD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1E,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE;YAAE,OAAO;QAE3C,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC5D,KAAK;YACL,UAAU;YACV,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,iBAAiB,CAAC;SAC7D,CAAC,CAAC,CAAC;QAEJ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,GAAU;QAC7B,KAAK,MAAM,GAAG,IAAI,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACrD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;YACzE,IAAI,CAAC,SAAS;gBAAE,SAAS;YACzB,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,2EAA2E;IAC3E,gCAAgC;IACxB,UAAU,CAAC,KAAY,EAAE,CAAC,MAAM,EAAE,OAAO,CAAoB;QACjE,IAAI,OAAO,IAAI,MAAM;YAAE,OAAO,KAAK,CAAC;QACpC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/F,CAAC;IAEO,aAAa,CAAC,GAAkB;QACpC,OAAO,IAAI,GAAG,CAAc,CAAC,CAAC,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC;IAEO,GAAG,CAAC,KAAc,EAAE,UAAmB;QAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IAC/C,CAAC;CAEJ;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ type TimeOfDay = {
2
+ hours: number;
3
+ minutes: number;
4
+ };
5
+ declare class Schedule {
6
+ private dayTest;
7
+ private times;
8
+ constructor(dayTest: (date: Date) => boolean, times: Array<TimeOfDay>);
9
+ getRuns(from: Date, to: Date): Array<Date>;
10
+ static daysOfWeek(days: Array<number>): (date: Date) => boolean;
11
+ static daysOfMonth(days: Array<number>): (date: Date) => boolean;
12
+ static everyDay(): (_date: Date) => boolean;
13
+ }
14
+ export { Schedule };
15
+ export type { TimeOfDay };
16
+ //# sourceMappingURL=Schedule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Schedule.d.ts","sourceRoot":"","sources":["../../src/scheduling/Schedule.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG;IAAE,KAAK,EAAG,MAAM,CAAC;IAAC,OAAO,EAAG,MAAM,CAAA;CAAE,CAAC;AAKtD,cAAM,QAAQ;IAEE,OAAO,CAAC,OAAO;IAA6B,OAAO,CAAC,KAAK;IAArE,YAAoB,OAAO,EAAG,CAAC,IAAI,EAAG,IAAI,KAAK,OAAO,EAAU,KAAK,EAAG,KAAK,CAAC,SAAS,CAAC,EAAI;IAG5F,OAAO,CAAC,IAAI,EAAG,IAAI,EAAE,EAAE,EAAG,IAAI,GAAI,KAAK,CAAC,IAAI,CAAC,CAiB5C;IAED,MAAM,CAAC,UAAU,CAAC,IAAI,EAAG,KAAK,CAAC,MAAM,CAAC,UACnB,IAAI,aACtB;IAED,MAAM,CAAC,WAAW,CAAC,IAAI,EAAG,KAAK,CAAC,MAAM,CAAC,UACpB,IAAI,aACtB;IAED,MAAM,CAAC,QAAQ,YACK,IAAI,aACvB;CAEJ;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,39 @@
1
+ /* Which days a machine runs on and at what times. The day test and the times
2
+ are separate so "weekdays at 09:00 and 17:00" and "the 1st of the month at
3
+ midnight" are the same shape. */
4
+ class Schedule {
5
+ dayTest;
6
+ times;
7
+ constructor(dayTest, times) {
8
+ this.dayTest = dayTest;
9
+ this.times = times;
10
+ }
11
+ // Runs strictly after `from` and up to and including `to`, in order.
12
+ getRuns(from, to) {
13
+ const runs = [];
14
+ const day = new Date(from);
15
+ day.setHours(0, 0, 0, 0);
16
+ for (; day.getTime() <= to.getTime(); day.setDate(day.getDate() + 1)) {
17
+ if (!this.dayTest(day))
18
+ continue;
19
+ for (const time of this.times) {
20
+ const run = new Date(day);
21
+ run.setHours(time.hours, time.minutes, 0, 0);
22
+ if (run.getTime() > from.getTime() && run.getTime() <= to.getTime())
23
+ runs.push(run);
24
+ }
25
+ }
26
+ return runs.sort((left, right) => left.getTime() - right.getTime());
27
+ }
28
+ static daysOfWeek(days) {
29
+ return (date) => days.includes(date.getDay());
30
+ }
31
+ static daysOfMonth(days) {
32
+ return (date) => days.includes(date.getDate());
33
+ }
34
+ static everyDay() {
35
+ return (_date) => true;
36
+ }
37
+ }
38
+ export { Schedule };
39
+ //# sourceMappingURL=Schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Schedule.js","sourceRoot":"","sources":["../../src/scheduling/Schedule.ts"],"names":[],"mappings":"AAEA;;mCAEmC;AACnC,MAAM,QAAQ;IAEU,OAAO;IAAqC,KAAK;IAArE,YAAoB,OAAkC,EAAU,KAAwB;uBAApE,OAAO;qBAAqC,KAAK;IAAsB,CAAC;IAE5F,qEAAqE;IACrE,OAAO,CAAC,IAAW,EAAE,EAAS;QAC1B,MAAM,IAAI,GAAiB,EAAE,CAAC;QAE9B,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAEzB,OAAO,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YACnE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,SAAS;YAEjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC7C,IAAI,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE;oBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxF,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,IAAoB;QAClC,OAAO,CAAC,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,IAAoB;QACnC,OAAO,CAAC,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,QAAQ;QACX,OAAO,CAAC,KAAY,EAAE,EAAE,CAAC,IAAI,CAAC;IAClC,CAAC;CAEJ;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric-state-machine",
3
- "version": "1.23.2",
3
+ "version": "1.24.0",
4
4
  "description": "This is the state machine library that one can use to add state management to an application. It will, by default, be locally runnable but can deployed to the Anbaric Cloud via the CLI",
5
5
  "license": "MIT",
6
6
  "author": "chris@anbaric.ai",
@@ -24,8 +24,8 @@
24
24
  "typescript": "^7.0.2"
25
25
  },
26
26
  "dependencies": {
27
- "anbaric-impl-cloud": "^1.23.2",
28
- "anbaric-tsapi": "^1.23.2"
27
+ "anbaric-impl-cloud": "^1.24.0",
28
+ "anbaric-tsapi": "^1.24.0"
29
29
  },
30
30
  "files": [
31
31
  "dist"