@actsecurity/job 0.1.63

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.
Files changed (61) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +9 -0
  3. package/dist/cjs/ConcurrentJobQueue.d.ts +65 -0
  4. package/dist/cjs/ConcurrentJobQueue.d.ts.map +1 -0
  5. package/dist/cjs/ConcurrentJobQueue.js +160 -0
  6. package/dist/cjs/ConcurrentJobQueue.js.map +1 -0
  7. package/dist/cjs/ConcurrentWorkerPool.d.ts +64 -0
  8. package/dist/cjs/ConcurrentWorkerPool.d.ts.map +1 -0
  9. package/dist/cjs/ConcurrentWorkerPool.js +166 -0
  10. package/dist/cjs/ConcurrentWorkerPool.js.map +1 -0
  11. package/dist/cjs/StreamingJobQueue.d.ts +63 -0
  12. package/dist/cjs/StreamingJobQueue.d.ts.map +1 -0
  13. package/dist/cjs/StreamingJobQueue.js +157 -0
  14. package/dist/cjs/StreamingJobQueue.js.map +1 -0
  15. package/dist/cjs/index.d.ts +7 -0
  16. package/dist/cjs/index.d.ts.map +1 -0
  17. package/dist/cjs/index.js +14 -0
  18. package/dist/cjs/index.js.map +1 -0
  19. package/dist/cjs/job.d.ts +36 -0
  20. package/dist/cjs/job.d.ts.map +1 -0
  21. package/dist/cjs/job.js +3 -0
  22. package/dist/cjs/job.js.map +1 -0
  23. package/dist/cjs/package.json +3 -0
  24. package/dist/cjs/runJobs.d.ts +13 -0
  25. package/dist/cjs/runJobs.d.ts.map +1 -0
  26. package/dist/cjs/runJobs.js +53 -0
  27. package/dist/cjs/runJobs.js.map +1 -0
  28. package/dist/cjs/util.d.ts +7 -0
  29. package/dist/cjs/util.d.ts.map +1 -0
  30. package/dist/cjs/util.js +13 -0
  31. package/dist/cjs/util.js.map +1 -0
  32. package/dist/esm/ConcurrentJobQueue.d.ts +65 -0
  33. package/dist/esm/ConcurrentJobQueue.d.ts.map +1 -0
  34. package/dist/esm/ConcurrentJobQueue.js +155 -0
  35. package/dist/esm/ConcurrentJobQueue.js.map +1 -0
  36. package/dist/esm/ConcurrentWorkerPool.d.ts +64 -0
  37. package/dist/esm/ConcurrentWorkerPool.d.ts.map +1 -0
  38. package/dist/esm/ConcurrentWorkerPool.js +161 -0
  39. package/dist/esm/ConcurrentWorkerPool.js.map +1 -0
  40. package/dist/esm/StreamingJobQueue.d.ts +63 -0
  41. package/dist/esm/StreamingJobQueue.d.ts.map +1 -0
  42. package/dist/esm/StreamingJobQueue.js +152 -0
  43. package/dist/esm/StreamingJobQueue.js.map +1 -0
  44. package/dist/esm/index.d.ts +7 -0
  45. package/dist/esm/index.d.ts.map +1 -0
  46. package/dist/esm/index.js +6 -0
  47. package/dist/esm/index.js.map +1 -0
  48. package/dist/esm/job.d.ts +36 -0
  49. package/dist/esm/job.d.ts.map +1 -0
  50. package/dist/esm/job.js +2 -0
  51. package/dist/esm/job.js.map +1 -0
  52. package/dist/esm/package.json +3 -0
  53. package/dist/esm/runJobs.d.ts +13 -0
  54. package/dist/esm/runJobs.d.ts.map +1 -0
  55. package/dist/esm/runJobs.js +51 -0
  56. package/dist/esm/runJobs.js.map +1 -0
  57. package/dist/esm/util.d.ts +7 -0
  58. package/dist/esm/util.d.ts.map +1 -0
  59. package/dist/esm/util.js +10 -0
  60. package/dist/esm/util.js.map +1 -0
  61. package/package.json +112 -0
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StreamingJobQueue = void 0;
4
+ /**
5
+ * A queue that will run jobs concurrently using promises up to a specified limit.
6
+ * If no work is being done, it will wait for jobs to be added and run them up to the
7
+ * maximum concurrency.
8
+ *
9
+ * Results are not stored in this queue, but are processed immediately via the `onComplete` callback.
10
+ *
11
+ */
12
+ class StreamingJobQueue {
13
+ concurrency;
14
+ logger;
15
+ onComplete;
16
+ queue = [];
17
+ activeJobs = 0;
18
+ waitingResolvers = [];
19
+ workers = [];
20
+ isAcceptingWork = true;
21
+ workAvailablePromise = null;
22
+ resolveWorkAvailable = null;
23
+ /**
24
+ * Create a new runner with the specified concurrency.
25
+ *
26
+ * @param concurrency - The maximum number of jobs to run concurrently.
27
+ * @param logger - Logger instance for long-running job warnings.
28
+ * @param onComplete - Callback to handle job completion, receives the job result.
29
+ */
30
+ constructor(concurrency, logger, onComplete) {
31
+ this.concurrency = concurrency;
32
+ this.logger = logger;
33
+ this.onComplete = onComplete;
34
+ }
35
+ async worker(workerId) {
36
+ while (this.isAcceptingWork || this.queue.length > 0) {
37
+ const job = this.queue.shift();
38
+ if (!job) {
39
+ if (!this.isAcceptingWork) {
40
+ // No longer accepting work and no jobs left, exit immediately
41
+ return;
42
+ }
43
+ // No work available, wait for new work to be added
44
+ await this.waitForWorkAvailable();
45
+ continue;
46
+ }
47
+ this.activeJobs++;
48
+ const context = { workerId };
49
+ const startTime = Date.now();
50
+ const interval = setInterval(() => {
51
+ this.logger.warn(`Long-running job detected.`, { minutes: Math.floor((Date.now() - startTime) / 60000) }, { ...context, ...job.properties });
52
+ }, 60_000);
53
+ try {
54
+ const value = await job.execute({ ...context, properties: job.properties });
55
+ // this.results.push({ status: 'fulfilled', value, properties: job.properties })
56
+ await this.onComplete({ status: 'fulfilled', value, properties: job.properties });
57
+ }
58
+ catch (reason) {
59
+ // this.results.push({ status: 'rejected', reason, properties: job.properties })
60
+ await this.onComplete({ status: 'rejected', reason, properties: job.properties });
61
+ }
62
+ finally {
63
+ clearInterval(interval);
64
+ this.activeJobs--;
65
+ this.checkIfIdle();
66
+ }
67
+ }
68
+ }
69
+ waitForWorkAvailable() {
70
+ if (!this.workAvailablePromise) {
71
+ this.workAvailablePromise = new Promise((resolve) => {
72
+ this.resolveWorkAvailable = resolve;
73
+ });
74
+ }
75
+ return this.workAvailablePromise;
76
+ }
77
+ ensureWorkers() {
78
+ if (this.workers.length === 0 && this.isAcceptingWork) {
79
+ for (let i = 0; i < this.concurrency; i++) {
80
+ this.workers.push(this.worker(i + 1));
81
+ }
82
+ }
83
+ }
84
+ notifyWorkersOfNewWork() {
85
+ // Wake up waiting workers
86
+ if (this.resolveWorkAvailable) {
87
+ this.resolveWorkAvailable();
88
+ this.workAvailablePromise = null;
89
+ this.resolveWorkAvailable = null;
90
+ }
91
+ }
92
+ checkIfIdle() {
93
+ if (this.activeJobs === 0 && this.queue.length === 0) {
94
+ // Notify all waiting resolvers
95
+ this.waitingResolvers.forEach((resolve) => resolve());
96
+ this.waitingResolvers = [];
97
+ }
98
+ }
99
+ /**
100
+ * Add a job to the queue
101
+ */
102
+ enqueue(job) {
103
+ if (!this.isAcceptingWork) {
104
+ throw new Error('Cannot enqueue jobs after shutdown');
105
+ }
106
+ this.queue.push(job);
107
+ this.ensureWorkers();
108
+ this.notifyWorkersOfNewWork();
109
+ }
110
+ /**
111
+ * Add multiple jobs to the queue
112
+ */
113
+ enqueueAll(jobs) {
114
+ jobs.forEach((job) => this.enqueue(job));
115
+ }
116
+ /**
117
+ * Returns a promise that resolves when all queued work is complete
118
+ */
119
+ waitForIdle() {
120
+ return new Promise((resolve) => {
121
+ if (this.activeJobs === 0 && this.queue.length === 0) {
122
+ resolve();
123
+ }
124
+ else {
125
+ this.waitingResolvers.push(resolve);
126
+ }
127
+ });
128
+ }
129
+ /**
130
+ * Shutdown the queue - no new jobs will be accepted, but existing jobs will complete.
131
+ *
132
+ * Returns when a promise that resolves when all jobs have been processed and
133
+ * the onComplete callback has been called for each job.
134
+ */
135
+ async finishAllWork() {
136
+ this.isAcceptingWork = false;
137
+ // Wake up any sleeping workers so they can process remaining jobs or exit
138
+ this.notifyWorkersOfNewWork();
139
+ // Check if we're already idle and notify any waiting resolvers
140
+ await Promise.all(this.workers);
141
+ this.workers = [];
142
+ }
143
+ /**
144
+ * Get the current queue length
145
+ */
146
+ get queueLength() {
147
+ return this.queue.length;
148
+ }
149
+ /**
150
+ * Get the number of currently active jobs
151
+ */
152
+ get activeJobCount() {
153
+ return this.activeJobs;
154
+ }
155
+ }
156
+ exports.StreamingJobQueue = StreamingJobQueue;
157
+ //# sourceMappingURL=StreamingJobQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StreamingJobQueue.js","sourceRoot":"","sources":["../../src/StreamingJobQueue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { ConcurrentJobQueue } from './ConcurrentJobQueue.js';
2
+ export { ConcurrentWorkerPool } from './ConcurrentWorkerPool.js';
3
+ export type { Job, JobContext, JobResult } from './job.js';
4
+ export { runJobs } from './runJobs.js';
5
+ export { StreamingJobQueue } from './StreamingJobQueue.js';
6
+ export { numberOfCpus } from './util.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.numberOfCpus = exports.StreamingJobQueue = exports.runJobs = exports.ConcurrentWorkerPool = exports.ConcurrentJobQueue = void 0;
4
+ var ConcurrentJobQueue_js_1 = require("./ConcurrentJobQueue.js");
5
+ Object.defineProperty(exports, "ConcurrentJobQueue", { enumerable: true, get: function () { return ConcurrentJobQueue_js_1.ConcurrentJobQueue; } });
6
+ var ConcurrentWorkerPool_js_1 = require("./ConcurrentWorkerPool.js");
7
+ Object.defineProperty(exports, "ConcurrentWorkerPool", { enumerable: true, get: function () { return ConcurrentWorkerPool_js_1.ConcurrentWorkerPool; } });
8
+ var runJobs_js_1 = require("./runJobs.js");
9
+ Object.defineProperty(exports, "runJobs", { enumerable: true, get: function () { return runJobs_js_1.runJobs; } });
10
+ var StreamingJobQueue_js_1 = require("./StreamingJobQueue.js");
11
+ Object.defineProperty(exports, "StreamingJobQueue", { enumerable: true, get: function () { return StreamingJobQueue_js_1.StreamingJobQueue; } });
12
+ var util_js_1 = require("./util.js");
13
+ Object.defineProperty(exports, "numberOfCpus", { enumerable: true, get: function () { return util_js_1.numberOfCpus; } });
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,iEAA4D;AAAnD,2HAAA,kBAAkB,OAAA;AAC3B,qEAAgE;AAAvD,+HAAA,oBAAoB,OAAA;AAE7B,2CAAsC;AAA7B,qGAAA,OAAO,OAAA;AAChB,+DAA0D;AAAjD,yHAAA,iBAAiB,OAAA;AAC1B,qCAAwC;AAA/B,uGAAA,YAAY,OAAA"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Represents the outcome of a job:
3
+ * - `fulfilled` with a `value` if it succeeded
4
+ * - `rejected` with a `reason` if it threw.
5
+ */
6
+ export type JobResult<T, P> = {
7
+ status: 'fulfilled';
8
+ value: T;
9
+ properties: P;
10
+ } | {
11
+ status: 'rejected';
12
+ reason: any;
13
+ properties: P;
14
+ };
15
+ export interface JobContext {
16
+ workerId: number;
17
+ }
18
+ /**
19
+ * Represents a job that can be executed
20
+ */
21
+ export interface Job<T = void, P = Record<string, unknown>> {
22
+ /**
23
+ * Execute the job with the given context.
24
+ *
25
+ * @param context - The context for the job execution, see @link JobContext
26
+ * @returns A promise that is resolved by the job's worker
27
+ */
28
+ execute: (props: JobContext & {
29
+ properties: P;
30
+ }) => Promise<T>;
31
+ /**
32
+ * Properties associated with the job, useful for logging or tracking.
33
+ */
34
+ properties: P;
35
+ }
36
+ //# sourceMappingURL=job.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../src/job.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,IACtB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC;IAAC,UAAU,EAAE,CAAC,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,UAAU,EAAE,CAAC,CAAA;CAAE,CAAA;AAEtD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD;;;;;OAKG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,UAAU,EAAE,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IAE9D;;OAEG;IACH,UAAU,EAAE,CAAC,CAAA;CACd"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=job.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../../src/job.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,13 @@
1
+ import { type Logger } from '@cloud-copilot/log';
2
+ import { type Job, type JobResult } from './job.js';
3
+ /**
4
+ * Runs the given jobs with up to `concurrency` tasks in flight at once.
5
+ * Resolves with an array of results in the same order as the jobs.
6
+ *
7
+ * @param jobs - The jobs to run
8
+ * @param concurrency - The maximum number of jobs to run concurrently
9
+ * @param logger - Optional logger instance for long-running job warnings. Defaults to the module-level logger from @cloud-copilot/log.
10
+ * @returns An array of results in the same order as the jobs
11
+ */
12
+ export declare function runJobs<T = void, P = Record<string, unknown>>(jobs: Job<T, P>[], concurrency: number, logger?: Logger): Promise<JobResult<T, P>[]>;
13
+ //# sourceMappingURL=runJobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runJobs.d.ts","sourceRoot":"","sources":["../../src/runJobs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,EAAE,KAAK,GAAG,EAAmB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpE;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EACjB,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,MAAsB,GAC7B,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CA6C5B"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runJobs = runJobs;
4
+ const log_1 = require("@cloud-copilot/log");
5
+ /**
6
+ * Runs the given jobs with up to `concurrency` tasks in flight at once.
7
+ * Resolves with an array of results in the same order as the jobs.
8
+ *
9
+ * @param jobs - The jobs to run
10
+ * @param concurrency - The maximum number of jobs to run concurrently
11
+ * @param logger - Optional logger instance for long-running job warnings. Defaults to the module-level logger from @cloud-copilot/log.
12
+ * @returns An array of results in the same order as the jobs
13
+ */
14
+ async function runJobs(jobs, concurrency, logger = log_1.log) {
15
+ const results = [];
16
+ let nextIndex = 0;
17
+ if (concurrency == null || concurrency === undefined || concurrency <= 0) {
18
+ throw new Error(`Invalid concurrency: ${concurrency}. Must be a positive integer.`);
19
+ }
20
+ // Each worker pulls the next available job, runs it, stores the result, then loops.
21
+ async function worker(workerId) {
22
+ while (true) {
23
+ const i = nextIndex++;
24
+ if (i >= jobs.length)
25
+ return;
26
+ const context = {
27
+ workerId
28
+ };
29
+ const startTime = Date.now();
30
+ const interval = setInterval(() => {
31
+ logger.warn(`Long-running job detected.`, { minutes: Math.floor((Date.now() - startTime) / 60000) }, { ...context, ...jobs[i].properties });
32
+ }, 60_000);
33
+ try {
34
+ const value = await jobs[i].execute({ ...context, properties: jobs[i].properties });
35
+ results[i] = { status: 'fulfilled', value, properties: jobs[i].properties };
36
+ }
37
+ catch (reason) {
38
+ results[i] = { status: 'rejected', reason, properties: jobs[i].properties };
39
+ }
40
+ finally {
41
+ clearInterval(interval);
42
+ }
43
+ }
44
+ }
45
+ // Create a pool of workers maxed at `concurrency` up to the number of jobs.
46
+ const workers = Array(Math.min(concurrency, jobs.length))
47
+ .fill(null)
48
+ .map((_, idx) => worker(idx + 1));
49
+ // Wait for all workers to finish
50
+ await Promise.all(workers);
51
+ return results;
52
+ }
53
+ //# sourceMappingURL=runJobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runJobs.js","sourceRoot":"","sources":["../../src/runJobs.ts"],"names":[],"mappings":";;AAYA,0BAiDC;AA7DD,4CAAsE;AAGtE;;;;;;;;GAQG;AACI,KAAK,UAAU,OAAO,CAC3B,IAAiB,EACjB,WAAmB,EACnB,SAAiB,SAAa;IAE9B,MAAM,OAAO,GAAsB,EAAE,CAAA;IACrC,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,IAAI,WAAW,IAAI,IAAI,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,wBAAwB,WAAW,+BAA+B,CAAC,CAAA;IACrF,CAAC;IAED,oFAAoF;IACpF,KAAK,UAAU,MAAM,CAAC,QAAgB;QACpC,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,SAAS,EAAE,CAAA;YACrB,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAM;YAE5B,MAAM,OAAO,GAAe;gBAC1B,QAAQ;aACT,CAAA;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC5B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;gBAChC,MAAM,CAAC,IAAI,CACT,4BAA4B,EAC5B,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,EAAE,EACzD,EAAE,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CACtC,CAAA;YACH,CAAC,EAAE,MAAM,CAAC,CAAA;YACV,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAA;gBACnF,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;YAC7E,CAAC;YAAC,OAAO,MAAM,EAAE,CAAC;gBAChB,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;YAC7E,CAAC;oBAAS,CAAC;gBACT,aAAa,CAAC,QAAQ,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;SACtD,IAAI,CAAC,IAAI,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;IAEnC,iCAAiC;IACjC,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAE1B,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Get the number of CPU cores available on the system.
3
+ *
4
+ * @returns The number of CPU cores, or 1 if the system cannot determine it.
5
+ */
6
+ export declare function numberOfCpus(): number;
7
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.numberOfCpus = numberOfCpus;
4
+ const os_1 = require("os");
5
+ /**
6
+ * Get the number of CPU cores available on the system.
7
+ *
8
+ * @returns The number of CPU cores, or 1 if the system cannot determine it.
9
+ */
10
+ function numberOfCpus() {
11
+ return (0, os_1.cpus)().length || 1;
12
+ }
13
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":";;AAOA,oCAEC;AATD,2BAAyB;AAEzB;;;;GAIG;AACH,SAAgB,YAAY;IAC1B,OAAO,IAAA,SAAI,GAAE,CAAC,MAAM,IAAI,CAAC,CAAA;AAC3B,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { type Logger } from '@cloud-copilot/log';
2
+ import { type Job, type JobResult } from './job.js';
3
+ /**
4
+ * Creates a queue that runs jobs concurrently up to a specified limit.
5
+ * This will wait for jobs to be added to it and run them up the
6
+ * maximum concurrency.
7
+ *
8
+ * Results are available via `getResults()`.
9
+ */
10
+ export declare class ConcurrentJobQueue<T = void, P = Record<string, unknown>> {
11
+ private concurrency;
12
+ private logger;
13
+ private queue;
14
+ private results;
15
+ private activeJobs;
16
+ private waitingResolvers;
17
+ private workers;
18
+ private isAcceptingWork;
19
+ private workAvailablePromise;
20
+ private resolveWorkAvailable;
21
+ /**
22
+ * Create a new runner with the specified concurrency.
23
+ *
24
+ * @param concurrency - The maximum number of jobs to run concurrently.
25
+ * @param logger - Optional logger instance for long-running job warnings. Defaults to the module-level logger from @cloud-copilot/log.
26
+ */
27
+ constructor(concurrency: number, logger?: Logger);
28
+ private worker;
29
+ private waitForWorkAvailable;
30
+ private ensureWorkers;
31
+ private notifyWorkersOfNewWork;
32
+ private checkIfIdle;
33
+ /**
34
+ * Add a job to the queue
35
+ */
36
+ enqueue(job: Job<T, P>): void;
37
+ /**
38
+ * Add multiple jobs to the queue
39
+ */
40
+ enqueueAll(jobs: Job<T, P>[]): void;
41
+ /**
42
+ * Returns a promise that resolves when all queued work is complete
43
+ */
44
+ waitForIdle(): Promise<void>;
45
+ /**
46
+ * Get all results accumulated so far
47
+ */
48
+ getResults(): JobResult<T, P>[];
49
+ /**
50
+ * Shutdown the queue - no new jobs will be accepted, but existing jobs will complete.
51
+ *
52
+ * Returns when a promise that resolves when all jobs have been processed and
53
+ * are available in `getResults()`.
54
+ */
55
+ finishAllWork(): Promise<void>;
56
+ /**
57
+ * Get the current queue length
58
+ */
59
+ get queueLength(): number;
60
+ /**
61
+ * Get the number of currently active jobs
62
+ */
63
+ get activeJobCount(): number;
64
+ }
65
+ //# sourceMappingURL=ConcurrentJobQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConcurrentJobQueue.d.ts","sourceRoot":"","sources":["../../src/ConcurrentJobQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,EAAE,KAAK,GAAG,EAAmB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpE;;;;;;GAMG;AAEH,qBAAa,kBAAkB,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAiBjE,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM;IAjBhB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,eAAe,CAAO;IAC9B,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,oBAAoB,CAA4B;IAExD;;;;;OAKG;gBAEO,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,MAAsB;YAG1B,MAAM;IAsCpB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAS7B;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI;IAInC;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B;;OAEG;IACH,UAAU,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;IAI/B;;;;;OAKG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IASpC;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAE3B;CACF"}
@@ -0,0 +1,155 @@
1
+ import { log as defaultLogger } from '@cloud-copilot/log';
2
+ import {} from './job.js';
3
+ /**
4
+ * Creates a queue that runs jobs concurrently up to a specified limit.
5
+ * This will wait for jobs to be added to it and run them up the
6
+ * maximum concurrency.
7
+ *
8
+ * Results are available via `getResults()`.
9
+ */
10
+ export class ConcurrentJobQueue {
11
+ /**
12
+ * Create a new runner with the specified concurrency.
13
+ *
14
+ * @param concurrency - The maximum number of jobs to run concurrently.
15
+ * @param logger - Optional logger instance for long-running job warnings. Defaults to the module-level logger from @cloud-copilot/log.
16
+ */
17
+ constructor(concurrency, logger = defaultLogger) {
18
+ this.concurrency = concurrency;
19
+ this.logger = logger;
20
+ this.queue = [];
21
+ this.results = [];
22
+ this.activeJobs = 0;
23
+ this.waitingResolvers = [];
24
+ this.workers = [];
25
+ this.isAcceptingWork = true;
26
+ this.workAvailablePromise = null;
27
+ this.resolveWorkAvailable = null;
28
+ }
29
+ async worker(workerId) {
30
+ while (this.isAcceptingWork || this.queue.length > 0) {
31
+ const job = this.queue.shift();
32
+ if (!job) {
33
+ if (!this.isAcceptingWork) {
34
+ // No longer accepting work and no jobs left, exit immediately
35
+ return;
36
+ }
37
+ // No work available, wait for new work to be added
38
+ await this.waitForWorkAvailable();
39
+ continue;
40
+ }
41
+ this.activeJobs++;
42
+ const context = { workerId };
43
+ const startTime = Date.now();
44
+ const interval = setInterval(() => {
45
+ this.logger.warn(`Long-running job detected.`, { minutes: Math.floor((Date.now() - startTime) / 60000) }, { ...context, ...job.properties });
46
+ }, 60000);
47
+ try {
48
+ const value = await job.execute({ ...context, properties: job.properties });
49
+ this.results.push({ status: 'fulfilled', value, properties: job.properties });
50
+ }
51
+ catch (reason) {
52
+ this.results.push({ status: 'rejected', reason, properties: job.properties });
53
+ }
54
+ finally {
55
+ clearInterval(interval);
56
+ this.activeJobs--;
57
+ this.checkIfIdle();
58
+ }
59
+ }
60
+ }
61
+ waitForWorkAvailable() {
62
+ if (!this.workAvailablePromise) {
63
+ this.workAvailablePromise = new Promise((resolve) => {
64
+ this.resolveWorkAvailable = resolve;
65
+ });
66
+ }
67
+ return this.workAvailablePromise;
68
+ }
69
+ ensureWorkers() {
70
+ if (this.workers.length === 0 && this.isAcceptingWork) {
71
+ for (let i = 0; i < this.concurrency; i++) {
72
+ this.workers.push(this.worker(i + 1));
73
+ }
74
+ }
75
+ }
76
+ notifyWorkersOfNewWork() {
77
+ // Wake up waiting workers
78
+ if (this.resolveWorkAvailable) {
79
+ this.resolveWorkAvailable();
80
+ this.workAvailablePromise = null;
81
+ this.resolveWorkAvailable = null;
82
+ }
83
+ }
84
+ checkIfIdle() {
85
+ if (this.activeJobs === 0 && this.queue.length === 0) {
86
+ // Notify all waiting resolvers
87
+ this.waitingResolvers.forEach((resolve) => resolve());
88
+ this.waitingResolvers = [];
89
+ }
90
+ }
91
+ /**
92
+ * Add a job to the queue
93
+ */
94
+ enqueue(job) {
95
+ if (!this.isAcceptingWork) {
96
+ throw new Error('Cannot enqueue jobs after shutdown');
97
+ }
98
+ this.queue.push(job);
99
+ this.ensureWorkers();
100
+ this.notifyWorkersOfNewWork();
101
+ }
102
+ /**
103
+ * Add multiple jobs to the queue
104
+ */
105
+ enqueueAll(jobs) {
106
+ jobs.forEach((job) => this.enqueue(job));
107
+ }
108
+ /**
109
+ * Returns a promise that resolves when all queued work is complete
110
+ */
111
+ waitForIdle() {
112
+ // log.debug('waitForIdle called', this.activeJobs, this.queue.length)
113
+ return new Promise((resolve) => {
114
+ if (this.activeJobs === 0 && this.queue.length === 0) {
115
+ resolve();
116
+ }
117
+ else {
118
+ this.waitingResolvers.push(resolve);
119
+ }
120
+ });
121
+ }
122
+ /**
123
+ * Get all results accumulated so far
124
+ */
125
+ getResults() {
126
+ return this.results;
127
+ }
128
+ /**
129
+ * Shutdown the queue - no new jobs will be accepted, but existing jobs will complete.
130
+ *
131
+ * Returns when a promise that resolves when all jobs have been processed and
132
+ * are available in `getResults()`.
133
+ */
134
+ async finishAllWork() {
135
+ this.isAcceptingWork = false;
136
+ // Wake up any sleeping workers so they can process remaining jobs or exit
137
+ this.notifyWorkersOfNewWork();
138
+ // Check if we're already idle and notify any waiting resolvers
139
+ await Promise.all(this.workers);
140
+ this.workers = [];
141
+ }
142
+ /**
143
+ * Get the current queue length
144
+ */
145
+ get queueLength() {
146
+ return this.queue.length;
147
+ }
148
+ /**
149
+ * Get the number of currently active jobs
150
+ */
151
+ get activeJobCount() {
152
+ return this.activeJobs;
153
+ }
154
+ }
155
+ //# sourceMappingURL=ConcurrentJobQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConcurrentJobQueue.js","sourceRoot":"","sources":["../../src/ConcurrentJobQueue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { type Logger } from '@cloud-copilot/log';
2
+ import { type Job, type JobResult } from './job.js';
3
+ /**
4
+ * A worker pool that will run jobs concurrently using promises up to a specified limit.
5
+ * If no work is being done, it will wait for jobs to be added and run them up to the
6
+ * maximum concurrency.
7
+ *
8
+ * This is designed to create a central queue for jobs of many types to be processed
9
+ * in a streaming fashion, allowing for efficient resource usage and managed network requests.
10
+ *
11
+ */
12
+ export declare class ConcurrentWorkerPool<T = void, P = Record<string, unknown>> {
13
+ private concurrency;
14
+ private logger;
15
+ private jobCounter;
16
+ private resolveMap;
17
+ private queue;
18
+ private activeJobs;
19
+ private waitingResolvers;
20
+ private workers;
21
+ private isAcceptingWork;
22
+ private workAvailablePromise;
23
+ private resolveWorkAvailable;
24
+ /**
25
+ * Create a new runner with the specified concurrency.
26
+ *
27
+ * @param concurrency - The maximum number of jobs to run concurrently.
28
+ * @param logger - Optional logger instance for long-running job warnings. Defaults to the module-level logger from @cloud-copilot/log.
29
+ */
30
+ constructor(concurrency: number, logger?: Logger);
31
+ private worker;
32
+ private waitForWorkAvailable;
33
+ private ensureWorkers;
34
+ private notifyWorkersOfNewWork;
35
+ private checkIfIdle;
36
+ /**
37
+ * Add a job to the queue
38
+ */
39
+ enqueue(job: Job<T, P>): Promise<JobResult<T, P>>;
40
+ /**
41
+ * Add multiple jobs to the queue
42
+ */
43
+ enqueueAll(jobs: Job<T, P>[]): Promise<JobResult<T, P>>[];
44
+ /**
45
+ * Returns a promise that resolves when all queued work is complete
46
+ */
47
+ waitForIdle(): Promise<void>;
48
+ /**
49
+ * Shutdown the queue - no new jobs will be accepted, but existing jobs will complete.
50
+ *
51
+ * Returns when a promise that resolves when all jobs have been processed and
52
+ * the onComplete callback has been called for each job.
53
+ */
54
+ finishAllWork(): Promise<void>;
55
+ /**
56
+ * Get the current queue length
57
+ */
58
+ get queueLength(): number;
59
+ /**
60
+ * Get the number of currently active jobs
61
+ */
62
+ get activeJobCount(): number;
63
+ }
64
+ //# sourceMappingURL=ConcurrentWorkerPool.d.ts.map