@naturalcycles/js-lib 15.93.1 → 15.93.2
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/promise/pGradualQueue.d.ts +7 -1
- package/dist/promise/pGradualQueue.js +40 -33
- package/dist/promise/pQueue.d.ts +7 -1
- package/dist/promise/pQueue.js +56 -49
- package/package.json +1 -1
- package/src/promise/pGradualQueue.ts +48 -39
- package/src/promise/pQueue.ts +62 -51
|
@@ -52,7 +52,13 @@ export declare class PGradualQueue {
|
|
|
52
52
|
* Push PromiseReturningFunction to the Queue.
|
|
53
53
|
* Returns a Promise that resolves (or rejects) with the return value from the Promise.
|
|
54
54
|
*/
|
|
55
|
-
push<R>(
|
|
55
|
+
push<R>(fn: AsyncFunction<R>): Promise<R>;
|
|
56
|
+
/**
|
|
57
|
+
* Starts the job and settles its `defer`.
|
|
58
|
+
* Intentionally not async: it's called both from `push` and when a running job finishes,
|
|
59
|
+
* and must not create a Promise that nobody handles (which would cause UnhandledRejection).
|
|
60
|
+
*/
|
|
61
|
+
private start;
|
|
56
62
|
get queueSize(): number;
|
|
57
63
|
/**
|
|
58
64
|
* Current concurrency limit based on warmup progress.
|
|
@@ -48,48 +48,55 @@ export class PGradualQueue {
|
|
|
48
48
|
* Push PromiseReturningFunction to the Queue.
|
|
49
49
|
* Returns a Promise that resolves (or rejects) with the return value from the Promise.
|
|
50
50
|
*/
|
|
51
|
-
async push(
|
|
51
|
+
async push(fn) {
|
|
52
52
|
// Initialize start time on first push
|
|
53
53
|
if (this.startTime === 0) {
|
|
54
54
|
this.startTime = Date.now();
|
|
55
55
|
}
|
|
56
|
-
const {
|
|
57
|
-
const fn = fn_;
|
|
58
|
-
fn.defer ||= pDefer();
|
|
56
|
+
const job = { fn, defer: pDefer() };
|
|
59
57
|
const concurrency = this.getCurrentConcurrency();
|
|
60
58
|
if (this.inFlight < concurrency) {
|
|
61
|
-
this.
|
|
62
|
-
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`);
|
|
63
|
-
runSafe(fn)
|
|
64
|
-
.then(result => {
|
|
65
|
-
fn.defer.resolve(result);
|
|
66
|
-
})
|
|
67
|
-
.catch((err) => {
|
|
68
|
-
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
69
|
-
logger.error(err);
|
|
70
|
-
fn.defer.resolve(); // resolve with `void`
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
fn.defer.reject(err);
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
.finally(() => {
|
|
77
|
-
this.inFlight--;
|
|
78
|
-
const currentConcurrency = this.getCurrentConcurrency();
|
|
79
|
-
logger.debug(`inFlight-- ${this.inFlight}/${currentConcurrency}, queue ${this.queue.length}`);
|
|
80
|
-
// Start queued jobs up to the current concurrency limit
|
|
81
|
-
// Use while loop since concurrency may have increased during warmup
|
|
82
|
-
while (this.queue.length && this.inFlight < this.getCurrentConcurrency()) {
|
|
83
|
-
const nextFn = this.queue.shift();
|
|
84
|
-
void this.push(nextFn);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
59
|
+
this.start(job, concurrency);
|
|
87
60
|
}
|
|
88
61
|
else {
|
|
89
|
-
this.queue.push(
|
|
90
|
-
logger.debug(`inFlight ${this.inFlight}/${concurrency}, queue++ ${this.queue.length}`);
|
|
62
|
+
this.queue.push(job);
|
|
63
|
+
this.logger.debug(`inFlight ${this.inFlight}/${concurrency}, queue++ ${this.queue.length}`);
|
|
91
64
|
}
|
|
92
|
-
return await
|
|
65
|
+
return await job.defer;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Starts the job and settles its `defer`.
|
|
69
|
+
* Intentionally not async: it's called both from `push` and when a running job finishes,
|
|
70
|
+
* and must not create a Promise that nobody handles (which would cause UnhandledRejection).
|
|
71
|
+
*/
|
|
72
|
+
start(job, concurrency) {
|
|
73
|
+
const { logger } = this;
|
|
74
|
+
const { defer } = job;
|
|
75
|
+
this.inFlight++;
|
|
76
|
+
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`);
|
|
77
|
+
runSafe(job.fn)
|
|
78
|
+
.then(result => {
|
|
79
|
+
defer.resolve(result);
|
|
80
|
+
})
|
|
81
|
+
.catch((err) => {
|
|
82
|
+
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
83
|
+
logger.error(err);
|
|
84
|
+
defer.resolve(); // resolve with `void`
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
defer.reject(err);
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
.finally(() => {
|
|
91
|
+
this.inFlight--;
|
|
92
|
+
const currentConcurrency = this.getCurrentConcurrency();
|
|
93
|
+
logger.debug(`inFlight-- ${this.inFlight}/${currentConcurrency}, queue ${this.queue.length}`);
|
|
94
|
+
// Start queued jobs up to the current concurrency limit
|
|
95
|
+
// Use while loop since concurrency may have increased during warmup
|
|
96
|
+
while (this.queue.length && this.inFlight < currentConcurrency) {
|
|
97
|
+
this.start(this.queue.shift(), currentConcurrency);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
93
100
|
}
|
|
94
101
|
get queueSize() {
|
|
95
102
|
return this.queue.length;
|
package/dist/promise/pQueue.d.ts
CHANGED
|
@@ -49,7 +49,13 @@ export declare class PQueue {
|
|
|
49
49
|
* Push PromiseReturningFunction to the Queue.
|
|
50
50
|
* Returns a Promise that resolves (or rejects) with the return value from the Promise.
|
|
51
51
|
*/
|
|
52
|
-
push<R>(
|
|
52
|
+
push<R>(fn: AsyncFunction<R>): Promise<R>;
|
|
53
|
+
/**
|
|
54
|
+
* Starts the job and settles its `defer`.
|
|
55
|
+
* Intentionally not async: it's called both from `push` and when a running job finishes,
|
|
56
|
+
* and must not create a Promise that nobody handles (which would cause UnhandledRejection).
|
|
57
|
+
*/
|
|
58
|
+
private start;
|
|
53
59
|
get queueSize(): number;
|
|
54
60
|
/**
|
|
55
61
|
* Returns a Promise that resolves when the queue is Idle (next time, since the call).
|
package/dist/promise/pQueue.js
CHANGED
|
@@ -28,59 +28,66 @@ export class PQueue {
|
|
|
28
28
|
* Push PromiseReturningFunction to the Queue.
|
|
29
29
|
* Returns a Promise that resolves (or rejects) with the return value from the Promise.
|
|
30
30
|
*/
|
|
31
|
-
async push(
|
|
32
|
-
const {
|
|
33
|
-
|
|
34
|
-
const fn = fn_;
|
|
35
|
-
fn.defer ||= pDefer();
|
|
36
|
-
if (this.inFlight < concurrency) {
|
|
31
|
+
async push(fn) {
|
|
32
|
+
const job = { fn, defer: pDefer() };
|
|
33
|
+
if (this.inFlight < this.cfg.concurrency) {
|
|
37
34
|
// There is room for more jobs. Can start immediately
|
|
38
|
-
this.
|
|
39
|
-
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`);
|
|
40
|
-
if (resolveOnStart)
|
|
41
|
-
fn.defer.resolve();
|
|
42
|
-
runSafe(fn)
|
|
43
|
-
.then(result => {
|
|
44
|
-
if (!resolveOnStart)
|
|
45
|
-
fn.defer.resolve(result);
|
|
46
|
-
})
|
|
47
|
-
.catch((err) => {
|
|
48
|
-
if (resolveOnStart) {
|
|
49
|
-
logger.error(err);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
53
|
-
logger.error(err);
|
|
54
|
-
fn.defer.resolve(); // resolve with `void`
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
// Should be handled on the outside, otherwise it'll cause UnhandledRejection
|
|
58
|
-
// Not logging, because it's re-thrown upstream
|
|
59
|
-
fn.defer.reject(err);
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
.finally(() => {
|
|
63
|
-
this.inFlight--;
|
|
64
|
-
logger.debug(`inFlight-- ${this.inFlight}/${concurrency}, queue ${this.queue.length}`);
|
|
65
|
-
// check if there's room to start next job
|
|
66
|
-
if (this.queue.length && this.inFlight <= concurrency) {
|
|
67
|
-
const nextFn = this.queue.shift();
|
|
68
|
-
void this.push(nextFn);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
if (this.inFlight === 0) {
|
|
72
|
-
logger.debug('onIdle');
|
|
73
|
-
this.onIdleListeners.forEach(defer => defer.resolve());
|
|
74
|
-
this.onIdleListeners.length = 0; // empty the array
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
});
|
|
35
|
+
this.start(job);
|
|
78
36
|
}
|
|
79
37
|
else {
|
|
80
|
-
this.queue.push(
|
|
81
|
-
logger.debug(`inFlight ${this.inFlight}/${concurrency}, queue++ ${this.queue.length}`);
|
|
38
|
+
this.queue.push(job);
|
|
39
|
+
this.logger.debug(`inFlight ${this.inFlight}/${this.cfg.concurrency}, queue++ ${this.queue.length}`);
|
|
82
40
|
}
|
|
83
|
-
return await
|
|
41
|
+
return await job.defer;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Starts the job and settles its `defer`.
|
|
45
|
+
* Intentionally not async: it's called both from `push` and when a running job finishes,
|
|
46
|
+
* and must not create a Promise that nobody handles (which would cause UnhandledRejection).
|
|
47
|
+
*/
|
|
48
|
+
start(job) {
|
|
49
|
+
const { concurrency } = this.cfg;
|
|
50
|
+
const { resolveOnStart, logger } = this;
|
|
51
|
+
const { defer } = job;
|
|
52
|
+
this.inFlight++;
|
|
53
|
+
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`);
|
|
54
|
+
if (resolveOnStart)
|
|
55
|
+
defer.resolve();
|
|
56
|
+
runSafe(job.fn)
|
|
57
|
+
.then(result => {
|
|
58
|
+
if (!resolveOnStart)
|
|
59
|
+
defer.resolve(result);
|
|
60
|
+
})
|
|
61
|
+
.catch((err) => {
|
|
62
|
+
if (resolveOnStart) {
|
|
63
|
+
logger.error(err);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
67
|
+
logger.error(err);
|
|
68
|
+
defer.resolve(); // resolve with `void`
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// Should be handled on the outside, otherwise it'll cause UnhandledRejection
|
|
72
|
+
// Not logging, because it's re-thrown upstream
|
|
73
|
+
defer.reject(err);
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.finally(() => {
|
|
77
|
+
this.inFlight--;
|
|
78
|
+
logger.debug(`inFlight-- ${this.inFlight}/${concurrency}, queue ${this.queue.length}`);
|
|
79
|
+
// check if there's room to start next job
|
|
80
|
+
if (this.queue.length && this.inFlight < concurrency) {
|
|
81
|
+
this.start(this.queue.shift());
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (this.inFlight === 0) {
|
|
85
|
+
logger.debug('onIdle');
|
|
86
|
+
this.onIdleListeners.forEach(defer => defer.resolve());
|
|
87
|
+
this.onIdleListeners.length = 0; // empty the array
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
84
91
|
}
|
|
85
92
|
get queueSize() {
|
|
86
93
|
return this.queue.length;
|
package/package.json
CHANGED
|
@@ -63,7 +63,7 @@ export class PGradualQueue {
|
|
|
63
63
|
private warmupComplete: boolean
|
|
64
64
|
|
|
65
65
|
inFlight = 0
|
|
66
|
-
private queue:
|
|
66
|
+
private queue: PGradualQueueJob<any>[] = []
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Get current allowed concurrency based on warmup progress.
|
|
@@ -89,54 +89,62 @@ export class PGradualQueue {
|
|
|
89
89
|
* Push PromiseReturningFunction to the Queue.
|
|
90
90
|
* Returns a Promise that resolves (or rejects) with the return value from the Promise.
|
|
91
91
|
*/
|
|
92
|
-
async push<R>(
|
|
92
|
+
async push<R>(fn: AsyncFunction<R>): Promise<R> {
|
|
93
93
|
// Initialize start time on first push
|
|
94
94
|
if (this.startTime === 0) {
|
|
95
95
|
this.startTime = Date.now()
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
const {
|
|
99
|
-
const fn = fn_ as AsyncFunctionWithDefer<R>
|
|
100
|
-
fn.defer ||= pDefer<R>()
|
|
101
|
-
|
|
98
|
+
const job: PGradualQueueJob<R> = { fn, defer: pDefer<R>() }
|
|
102
99
|
const concurrency = this.getCurrentConcurrency()
|
|
103
100
|
|
|
104
101
|
if (this.inFlight < concurrency) {
|
|
105
|
-
this.
|
|
106
|
-
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`)
|
|
107
|
-
|
|
108
|
-
runSafe(fn)
|
|
109
|
-
.then(result => {
|
|
110
|
-
fn.defer.resolve(result)
|
|
111
|
-
})
|
|
112
|
-
.catch((err: Error) => {
|
|
113
|
-
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
114
|
-
logger.error(err)
|
|
115
|
-
fn.defer.resolve() // resolve with `void`
|
|
116
|
-
} else {
|
|
117
|
-
fn.defer.reject(err)
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
.finally(() => {
|
|
121
|
-
this.inFlight--
|
|
122
|
-
const currentConcurrency = this.getCurrentConcurrency()
|
|
123
|
-
logger.debug(
|
|
124
|
-
`inFlight-- ${this.inFlight}/${currentConcurrency}, queue ${this.queue.length}`,
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
// Start queued jobs up to the current concurrency limit
|
|
128
|
-
// Use while loop since concurrency may have increased during warmup
|
|
129
|
-
while (this.queue.length && this.inFlight < this.getCurrentConcurrency()) {
|
|
130
|
-
const nextFn = this.queue.shift()!
|
|
131
|
-
void this.push(nextFn)
|
|
132
|
-
}
|
|
133
|
-
})
|
|
102
|
+
this.start(job, concurrency)
|
|
134
103
|
} else {
|
|
135
|
-
this.queue.push(
|
|
136
|
-
logger.debug(`inFlight ${this.inFlight}/${concurrency}, queue++ ${this.queue.length}`)
|
|
104
|
+
this.queue.push(job)
|
|
105
|
+
this.logger.debug(`inFlight ${this.inFlight}/${concurrency}, queue++ ${this.queue.length}`)
|
|
137
106
|
}
|
|
138
107
|
|
|
139
|
-
return await
|
|
108
|
+
return await job.defer
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Starts the job and settles its `defer`.
|
|
113
|
+
* Intentionally not async: it's called both from `push` and when a running job finishes,
|
|
114
|
+
* and must not create a Promise that nobody handles (which would cause UnhandledRejection).
|
|
115
|
+
*/
|
|
116
|
+
private start<R>(job: PGradualQueueJob<R>, concurrency: number): void {
|
|
117
|
+
const { logger } = this
|
|
118
|
+
const { defer } = job
|
|
119
|
+
|
|
120
|
+
this.inFlight++
|
|
121
|
+
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`)
|
|
122
|
+
|
|
123
|
+
runSafe(job.fn)
|
|
124
|
+
.then(result => {
|
|
125
|
+
defer.resolve(result)
|
|
126
|
+
})
|
|
127
|
+
.catch((err: Error) => {
|
|
128
|
+
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
129
|
+
logger.error(err)
|
|
130
|
+
defer.resolve() // resolve with `void`
|
|
131
|
+
} else {
|
|
132
|
+
defer.reject(err)
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
.finally(() => {
|
|
136
|
+
this.inFlight--
|
|
137
|
+
const currentConcurrency = this.getCurrentConcurrency()
|
|
138
|
+
logger.debug(
|
|
139
|
+
`inFlight-- ${this.inFlight}/${currentConcurrency}, queue ${this.queue.length}`,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
// Start queued jobs up to the current concurrency limit
|
|
143
|
+
// Use while loop since concurrency may have increased during warmup
|
|
144
|
+
while (this.queue.length && this.inFlight < currentConcurrency) {
|
|
145
|
+
this.start(this.queue.shift()!, currentConcurrency)
|
|
146
|
+
}
|
|
147
|
+
})
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
get queueSize(): number {
|
|
@@ -164,6 +172,7 @@ function runSafe<R>(fn: AsyncFunction<R>): Promise<R> {
|
|
|
164
172
|
}
|
|
165
173
|
}
|
|
166
174
|
|
|
167
|
-
interface
|
|
175
|
+
interface PGradualQueueJob<R> {
|
|
176
|
+
fn: AsyncFunction<R>
|
|
168
177
|
defer: DeferredPromise<R>
|
|
169
178
|
}
|
package/src/promise/pQueue.ts
CHANGED
|
@@ -61,67 +61,77 @@ export class PQueue {
|
|
|
61
61
|
private readonly logger: CommonLogger
|
|
62
62
|
|
|
63
63
|
inFlight = 0
|
|
64
|
-
private queue:
|
|
64
|
+
private queue: PQueueJob<any>[] = []
|
|
65
65
|
private onIdleListeners: DeferredPromise[] = []
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Push PromiseReturningFunction to the Queue.
|
|
69
69
|
* Returns a Promise that resolves (or rejects) with the return value from the Promise.
|
|
70
70
|
*/
|
|
71
|
-
async push<R>(
|
|
72
|
-
const {
|
|
73
|
-
const { resolveOnStart, logger } = this
|
|
71
|
+
async push<R>(fn: AsyncFunction<R>): Promise<R> {
|
|
72
|
+
const job: PQueueJob<R> = { fn, defer: pDefer<R>() }
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
fn.defer ||= pDefer<R>()
|
|
77
|
-
|
|
78
|
-
if (this.inFlight < concurrency) {
|
|
74
|
+
if (this.inFlight < this.cfg.concurrency) {
|
|
79
75
|
// There is room for more jobs. Can start immediately
|
|
80
|
-
this.
|
|
81
|
-
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`)
|
|
82
|
-
if (resolveOnStart) fn.defer.resolve()
|
|
83
|
-
|
|
84
|
-
runSafe(fn)
|
|
85
|
-
.then(result => {
|
|
86
|
-
if (!resolveOnStart) fn.defer.resolve(result)
|
|
87
|
-
})
|
|
88
|
-
.catch((err: Error) => {
|
|
89
|
-
if (resolveOnStart) {
|
|
90
|
-
logger.error(err)
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
95
|
-
logger.error(err)
|
|
96
|
-
fn.defer.resolve() // resolve with `void`
|
|
97
|
-
} else {
|
|
98
|
-
// Should be handled on the outside, otherwise it'll cause UnhandledRejection
|
|
99
|
-
// Not logging, because it's re-thrown upstream
|
|
100
|
-
fn.defer.reject(err)
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
.finally(() => {
|
|
104
|
-
this.inFlight--
|
|
105
|
-
logger.debug(`inFlight-- ${this.inFlight}/${concurrency}, queue ${this.queue.length}`)
|
|
106
|
-
|
|
107
|
-
// check if there's room to start next job
|
|
108
|
-
if (this.queue.length && this.inFlight <= concurrency) {
|
|
109
|
-
const nextFn = this.queue.shift()!
|
|
110
|
-
void this.push(nextFn)
|
|
111
|
-
} else {
|
|
112
|
-
if (this.inFlight === 0) {
|
|
113
|
-
logger.debug('onIdle')
|
|
114
|
-
this.onIdleListeners.forEach(defer => defer.resolve())
|
|
115
|
-
this.onIdleListeners.length = 0 // empty the array
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
})
|
|
76
|
+
this.start(job)
|
|
119
77
|
} else {
|
|
120
|
-
this.queue.push(
|
|
121
|
-
logger.debug(
|
|
78
|
+
this.queue.push(job)
|
|
79
|
+
this.logger.debug(
|
|
80
|
+
`inFlight ${this.inFlight}/${this.cfg.concurrency}, queue++ ${this.queue.length}`,
|
|
81
|
+
)
|
|
122
82
|
}
|
|
123
83
|
|
|
124
|
-
return await
|
|
84
|
+
return await job.defer
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Starts the job and settles its `defer`.
|
|
89
|
+
* Intentionally not async: it's called both from `push` and when a running job finishes,
|
|
90
|
+
* and must not create a Promise that nobody handles (which would cause UnhandledRejection).
|
|
91
|
+
*/
|
|
92
|
+
private start<R>(job: PQueueJob<R>): void {
|
|
93
|
+
const { concurrency } = this.cfg
|
|
94
|
+
const { resolveOnStart, logger } = this
|
|
95
|
+
const { defer } = job
|
|
96
|
+
|
|
97
|
+
this.inFlight++
|
|
98
|
+
logger.debug(`inFlight++ ${this.inFlight}/${concurrency}, queue ${this.queue.length}`)
|
|
99
|
+
if (resolveOnStart) defer.resolve()
|
|
100
|
+
|
|
101
|
+
runSafe(job.fn)
|
|
102
|
+
.then(result => {
|
|
103
|
+
if (!resolveOnStart) defer.resolve(result)
|
|
104
|
+
})
|
|
105
|
+
.catch((err: Error) => {
|
|
106
|
+
if (resolveOnStart) {
|
|
107
|
+
logger.error(err)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.cfg.errorMode === ErrorMode.SUPPRESS) {
|
|
112
|
+
logger.error(err)
|
|
113
|
+
defer.resolve() // resolve with `void`
|
|
114
|
+
} else {
|
|
115
|
+
// Should be handled on the outside, otherwise it'll cause UnhandledRejection
|
|
116
|
+
// Not logging, because it's re-thrown upstream
|
|
117
|
+
defer.reject(err)
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
.finally(() => {
|
|
121
|
+
this.inFlight--
|
|
122
|
+
logger.debug(`inFlight-- ${this.inFlight}/${concurrency}, queue ${this.queue.length}`)
|
|
123
|
+
|
|
124
|
+
// check if there's room to start next job
|
|
125
|
+
if (this.queue.length && this.inFlight < concurrency) {
|
|
126
|
+
this.start(this.queue.shift()!)
|
|
127
|
+
} else {
|
|
128
|
+
if (this.inFlight === 0) {
|
|
129
|
+
logger.debug('onIdle')
|
|
130
|
+
this.onIdleListeners.forEach(defer => defer.resolve())
|
|
131
|
+
this.onIdleListeners.length = 0 // empty the array
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
})
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
get queueSize(): number {
|
|
@@ -155,6 +165,7 @@ function runSafe<R>(fn: AsyncFunction<R>): Promise<R> {
|
|
|
155
165
|
}
|
|
156
166
|
}
|
|
157
167
|
|
|
158
|
-
interface
|
|
168
|
+
interface PQueueJob<R> {
|
|
169
|
+
fn: AsyncFunction<R>
|
|
159
170
|
defer: DeferredPromise<R>
|
|
160
171
|
}
|