1
1
export type SemaphoreJob < T > = ( ) => Promise < T > ;
2
2
/**
3
- * ZeroBackpressureSemaphore
4
- *
5
3
* The `ZeroBackpressureSemaphore` class implements a semaphore for Node.js projects, allowing users
6
4
* to limit the number of concurrently executing jobs. This implementation does not queue pending
7
5
* jobs, thereby eliminating backpressure. As a result, users have better control over memory
@@ -24,7 +22,7 @@ export type SemaphoreJob<T> = () => Promise<T>;
24
22
* methods, reminiscent of the RAII idiom in C++.
25
23
* Method names are chosen to clearly convey their functionality.
26
24
*
27
- * ### Graceful Termination
25
+ * ### Graceful Teardown
28
26
* All the job execution promises are tracked by the semaphore instance, ensuring no dangling promises.
29
27
* This enables graceful termination via the `waitForAllExecutingJobsToComplete` method, in scenarios
30
28
* where it is essential to ensure that all the currently executing or pending jobs are fully processed
@@ -49,8 +47,6 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
49
47
private _notifyAvailableSlotExists ?;
50
48
private _uncaughtErrors ;
51
49
/**
52
- * Constructor.
53
- *
54
50
* Initializes the semaphore with the specified maximum number of concurrently
55
51
* executing jobs. This sets up the internal structures to enforce the concurrency
56
52
* limit for job execution.
@@ -60,26 +56,18 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
60
56
*/
61
57
constructor ( maxConcurrentJobs : number ) ;
62
58
/**
63
- * maxConcurrentJobs
64
- *
65
59
* @returns The maximum number of concurrent jobs as specified in the constructor.
66
60
*/
67
61
get maxConcurrentJobs ( ) : number ;
68
62
/**
69
- * isAvailable
70
- *
71
63
* @returns True if there is an available job slot, otherwise false.
72
64
*/
73
65
get isAvailable ( ) : boolean ;
74
66
/**
75
- * amountOfCurrentlyExecutingJobs
76
- *
77
67
* @returns The number of jobs currently being executed by the semaphore.
78
68
*/
79
69
get amountOfCurrentlyExecutingJobs ( ) : number ;
80
70
/**
81
- * amountOfUncaughtErrors
82
- *
83
71
* Indicates the number of uncaught errors from background jobs triggered by `startExecution`,
84
72
* that are currently stored by the instance.
85
73
* These errors have not yet been extracted using `extractUncaughtErrors`.
@@ -91,10 +79,8 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
91
79
*/
92
80
get amountOfUncaughtErrors ( ) : number ;
93
81
/**
94
- * startExecution
95
- *
96
- * This method resolves once the given job has *started* its execution, indicating that the
97
- * semaphore has become available (i.e., allotted a slot for the job).
82
+ * Resolves once the given job has *started* its execution, indicating that the semaphore has
83
+ * become available (i.e., allotted a slot for the job).
98
84
* Users can leverage this to prevent backpressure of pending jobs:
99
85
* If the semaphore is too busy to start a given job `X`, there is no reason to create another
100
86
* job `Y` until `X` has started.
@@ -103,7 +89,7 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
103
89
* value is expected. It promotes a just-in-time approach, on which each job is pending execution
104
90
* only when no other job is, thereby eliminating backpressure and reducing memory footprint.
105
91
*
106
- * ### Graceful Termination
92
+ * ### Graceful Teardown
107
93
* Method `waitForAllExecutingJobsToComplete` complements the typical use-cases of `startExecution`.
108
94
* It can be used to perform post-processing, after all the currently-executing jobs have completed.
109
95
*
@@ -112,34 +98,30 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
112
98
* `extractUncaughtError` method. Users are encouraged to specify a custom `UncaughtErrorType`
113
99
* generic parameter to the class if jobs may throw errors.
114
100
*
115
- * @param backgroundJob - The job to be executed once the semaphore is available.
101
+ * @param backgroundJob The job to be executed once the semaphore is available.
116
102
* @returns A promise that resolves when the job starts execution.
117
103
*/
118
104
startExecution ( backgroundJob : SemaphoreJob < T > ) : Promise < void > ;
119
105
/**
120
- * waitForCompletion
121
- *
122
- * This method executes the given job in a controlled manner, once the semaphore is available.
123
- * It resolves or rejects when the job finishes execution, returning the job's value or propagating
124
- * any error it may throw.
106
+ * Executes the given job in a controlled manner, once the semaphore is available.
107
+ * It resolves or rejects when the job finishes execution, returning the job's value or
108
+ * propagating any error it may throw.
125
109
*
126
- * This method is useful when the flow depends on a job's execution to proceed, such as needing
127
- * its return value or handling any errors it may throw.
110
+ * This method is useful when the flow depends on a job's execution to proceed, such as
111
+ * needing its return value or handling any errors it may throw.
128
112
*
129
113
* ### Example Use Case
130
114
* Suppose you have a route handler that needs to perform a specific code block with limited
131
115
* concurrency (e.g., database access) due to external constraints, such as throttling limits.
132
116
* This method allows you to execute the job with controlled concurrency. Once the job resolves
133
117
* or rejects, you can continue the route handler's flow based on the result.
134
118
*
135
- * @param job - The job to be executed once the semaphore is available.
136
- * @throws - Error thrown by the job itself.
119
+ * @param job The job to be executed once the semaphore is available.
120
+ * @throws Error thrown by the job itself.
137
121
* @returns A promise that resolves with the job's return value or rejects with its error.
138
122
*/
139
123
waitForCompletion ( job : SemaphoreJob < T > ) : Promise < T > ;
140
124
/**
141
- * waitForAllExecutingJobsToComplete
142
- *
143
125
* Waits for all **currently executing jobs** to finish, ensuring that all active promises
144
126
* have either resolved or rejected before proceeding. This enables graceful termination in
145
127
* scenarios such as:
@@ -150,27 +132,25 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
150
132
* By default, this method only waits for jobs that are already **executing** at the time of
151
133
* invocation. In other words, the default behavior does **not** consider potential jobs that
152
134
* are still queued (pending execution).
153
- * A backpressure of pending jobs may happen when multiple different callers share the same semaphore
154
- * instance, each being unaware of the others.
155
- * To extend the waiting behavior to include **potentially pending jobs** which account for backpressure,
156
- * use the optional `considerPendingJobsBackpressure` parameter set to `true`. When this flag is enabled,
157
- * the method will account for both existing and future backpressure, even if the backpressure arises
158
- * after the method is invoked.
159
- *
160
- * @param considerPendingJobsBackpressure A boolean indicating whether this method should also wait for
161
- * the resolution of all potentially queued jobs (i.e., those not
162
- * yet executed when the method was invoked).
135
+ * A backpressure of pending jobs may happen when multiple different callers share the same
136
+ * semaphore instance, each being unaware of the others.
137
+ * To extend the waiting behavior to include **potentially pending jobs** which account for
138
+ * backpressure, use the optional `considerPendingJobsBackpressure` parameter set to `true`.
139
+ * When this flag is enabled, the method will account for both existing and future backpressure,
140
+ * even if the backpressure arises after the method is invoked.
141
+ *
142
+ * @param considerPendingJobsBackpressure A boolean indicating whether this method should also wait
143
+ * for the resolution of all potentially queued jobs (i.e.,
144
+ * those not yet executed when the method was invoked).
163
145
* This is especially relevant when multiple different callers
164
- * share the same semaphore instance, each being unaware of the
165
- * others.
146
+ * share the same semaphore instance, each being unaware of
147
+ * the others.
166
148
* @returns A promise that resolves once all currently executing jobs have completed.
167
149
* If `considerPendingJobsBackpressure` is `true`, the promise will additionally
168
150
* wait until all queued jobs have been executed, ensuring no pending job backpressure remains.
169
151
*/
170
152
waitForAllExecutingJobsToComplete ( considerPendingJobsBackpressure ?: boolean ) : Promise < void > ;
171
153
/**
172
- * waitForAvailability
173
- *
174
154
* This method resolves once at least one slot is available for job execution.
175
155
* In other words, it resolves when the semaphore is available to trigger a new job immediately.
176
156
*
@@ -185,19 +165,19 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
185
165
* To prevent such potential backpressure, users can utilize the `waitForAvailability` method
186
166
* before consuming the next message.
187
167
*
188
- * ### Rarely Needed
189
- * This method can be useful when the system is experiencing high load (as indicated by CPU and/or memory
190
- * usage metrics), and you want to pause further async operations until an available job slot opens up.
168
+ * ### Design Choice
169
+ * This method can be useful when the system is experiencing high load (as indicated by CPU
170
+ * and/or memory usage metrics), and you want to pause further async operations until an available
171
+ * job slot opens up.
191
172
* However, the same effect can be achieved with `startExecution` alone if the async logic
192
- * (intended to be delayed until availability) is handled within the job itself rather than as a preliminary
193
- * step. Therefore, `waitForAvailability` serves as a design choice rather than a strict necessity.
173
+ * (intended to be delayed until availability) is handled within the job itself rather than as
174
+ * a preliminary step. Therefore, `waitForAvailability` serves as a design choice rather than a
175
+ * strict necessity.
194
176
*
195
177
* @returns A promise that resolves once at least one slot is available.
196
178
*/
197
179
waitForAvailability ( ) : Promise < void > ;
198
180
/**
199
- * extractUncaughtErrors
200
- *
201
181
* This method returns an array of uncaught errors, captured by the semaphore while executing
202
182
* background jobs added by `startExecution`. The term `extract` implies that the semaphore
203
183
* instance will no longer hold these error references once extracted, unlike `get`. In other
@@ -217,8 +197,6 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
217
197
extractUncaughtErrors ( ) : UncaughtErrorType [ ] ;
218
198
private _getAvailableSlot ;
219
199
/**
220
- * _handleJobExecution
221
- *
222
200
* This method manages the execution of a given job in a controlled manner. It ensures that
223
201
* the job is executed within the constraints of the semaphore and handles updating the
224
202
* internal state once the job has completed.
@@ -227,11 +205,11 @@ export declare class ZeroBackpressureSemaphore<T, UncaughtErrorType = Error> {
227
205
* - Waits for the job to either return a value or throw an error.
228
206
* - Updates the internal state to make the allotted slot available again once the job is finished.
229
207
*
230
- * @param job - The job to be executed in the given slot.
231
- * @param allottedSlot - The slot number in which the job should be executed.
232
- * @param isBackgroundJob - A flag indicating whether the caller expects a return value to proceed
233
- * with its work. If `true`, no return value is expected, and any error
234
- * thrown by the job should not be propagated.
208
+ * @param job The job to be executed in the given slot.
209
+ * @param allottedSlot The slot number in which the job should be executed.
210
+ * @param isBackgroundJob A flag indicating whether the caller expects a return value to proceed
211
+ * with its work. If `true`, no return value is expected, and any error
212
+ * thrown by the job should not be propagated.
235
213
* @returns A promise that resolves with the job's return value or rejects with its error.
236
214
* Rejection occurs only if triggered by `waitForCompletion`.
237
215
*/
0 commit comments