Skip to content

Commit ff4f4c9

Browse files
committed
Bump to version v1.0.3: README refinements and dev-dependencies update
1 parent b0ffded commit ff4f4c9

File tree

3 files changed

+58
-54
lines changed

3 files changed

+58
-54
lines changed

README.md

+40-40
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ The `ZeroBackpressureSemaphore` class implements a semaphore for Node.js project
44
This implementation does not queue pending jobs, thereby eliminating backpressure. As a result, users have better control over memory footprint, which enhances performance by reducing garbage-collector overhead.
55

66
The design addresses the two primary semaphore use cases in Node.js:
7-
* __Single Job Execution__: In scenarios where multiple callers, such as route handlers, concurrently access the same semaphore instance. Each caller initiates a single job and relies on its outcome to proceed.
87
* __Multiple Jobs Execution__: This use case involves a single caller dispatching multiple jobs, often serving as the sole owner of the semaphore instance.
8+
* __Single Job Execution__: In scenarios where multiple callers, such as route handlers, concurrently access the same semaphore instance. Each caller initiates a single job and relies on its outcome to proceed.
99

1010
Each use case necessitates distinct handling capabilities, which will be discussed separately with accompanying examples.
1111

@@ -33,44 +33,9 @@ npm i zero-backpressure-semaphore-typescript
3333
- High efficiency: All state-altering operations have a constant time complexity, O(1).
3434
- No external runtime dependencies: Only development dependencies are used.
3535

36-
## 1st use-case: Single Job Execution
37-
38-
The `waitForCompletion` method is useful for executing a sub-procedure, for which the caller must wait before proceeding with its work.
39-
40-
For example, consider fetching data from an external resource within a route handler. The route handler must respond (e.g., with an HTTP status 200 on success) based on the result of the fetching sub-procedure. Note that a sub-procedure may return a value or throw an error. If an error is thrown, `waitForCompletion` will propagate the error back to the caller.
41-
42-
The concurrency limit for such operations is typically set based on external constraints (e.g., reducing the chances of being throttled) or the desire to limit network resource usage.
43-
44-
```ts
45-
import { SemaphoreJob, ZeroBackpressureSemaphore } from 'zero-backpressure-semaphore-ts';
46-
47-
type UserInfo = Record<string, string>;
48-
49-
const maxConcurrentDbRequests = 32;
50-
const dbAccessSemaphore = new ZeroBackpressureSemaphore<UserInfo>(maxConcurrentDbRequests);
51-
52-
app.get('/user/', async (req, res) => {
53-
// Define the sub-prodecure.
54-
const fetchUserInfo: SemaphoreJob<UserInfo> = async (): Promise<UserInfo> => {
55-
const userInfo: UserInfo = await usersDbClient.get(req.userID);
56-
return userInfo;
57-
}
58-
59-
// Execute the sub-procedure in a controlled manner.
60-
try {
61-
const userInfo: UserInfo = await dbAccessSemaphore.waitForCompletion(fetchUserInfo);
62-
res.status(HTTP_OK_CODE).send(userInfo);
63-
} catch (err) {
64-
// err was thrown by the fetchUserInfo job.
65-
logger.error(`Failed fetching user info for userID ${req.userID} with error: ${err.message}`);
66-
res.status(HTTP_ERROR_CODE);
67-
}
68-
});
69-
```
70-
71-
## 2nd use-case: Multiple Jobs Execution
36+
## 1st use-case: Multiple Jobs Execution
7237

73-
Unlike the first use case, dispatching multiple concurrent jobs is more likely to cause backpressure. This pattern is typically observed in **background job services**, such as:
38+
This semaphore variant excels in eliminating backpressure when dispatching multiple concurrent jobs from the same caller. This pattern is typically observed in **background job services**, such as:
7439
- Log File analysis.
7540
- Network Traffic analyzers.
7641
- Vulnerability scanning.
@@ -79,10 +44,10 @@ Unlike the first use case, dispatching multiple concurrent jobs is more likely t
7944
- Remote Configuration changes.
8045
- Batch Data processing.
8146

82-
Here, the start time of each job is crucial. Since a pending job cannot start its execution until the semaphore allows, there is no benefit to adding additional jobs that cannot start immediately. The `startExecution` method communicates the job's start time to the caller (resolves as soon as the job starts), which enables to push a new job as-soon-as it makes sense.
47+
Here, the start time of each job is crucial. Since a pending job cannot start its execution until the semaphore allows, there is no benefit to adding additional jobs that cannot start immediately. The `startExecution` method communicates the job's start time to the caller (resolves as soon as the job starts), which enables to create a new job as-soon-as it makes sense.
8348

8449
For example, consider an application managing 100,000 IoT sensors that require hourly data aggregation. To mitigate server load, a semaphore can be employed to limit the number of concurrent data aggregation tasks.
85-
Rather than pre-creating 100,000 jobs (one for each sensor), which could potentially overwhelm the Node.js task queue and induce backpressure, the system should adopt a just-in-time approach. This means creating a sensor aggregation job only when the semaphore indicates availability, thereby optimizing resource utilization and maintaining system stability.
50+
Rather than pre-creating 100,000 jobs (one for each sensor), which could potentially overwhelm the Node.js task queue and induce backpressure, the system should adopt a **just-in-time** approach. This means creating a sensor aggregation job only when the semaphore indicates availability, thereby optimizing resource utilization and maintaining system stability.
8651

8752
Note: method `waitTillAllExecutingJobsAreSettled` can be used to perform post-processing, after all jobs have completed. It complements the typical use-cases of `startExecution`.
8853

@@ -109,6 +74,41 @@ async function aggregateSensorsData(sensorUIDs: ReadonlyArray<string>) {
10974
}
11075
```
11176

77+
## 2nd use-case: Single Job Execution
78+
79+
The `waitForCompletion` method is useful for executing a sub-procedure, for which the caller must wait before proceeding with its work.
80+
81+
For example, consider fetching data from an external resource within a route handler. The route handler must respond (e.g., with an HTTP status 200 on success) based on the result of the fetching sub-procedure. Note that a sub-procedure may return a value or throw an error. If an error is thrown, `waitForCompletion` will propagate the error back to the caller.
82+
83+
The concurrency limit for such operations is typically set based on external constraints (e.g., reducing the chances of being throttled) or the desire to limit network resource usage.
84+
85+
```ts
86+
import { SemaphoreJob, ZeroBackpressureSemaphore } from 'zero-backpressure-semaphore-ts';
87+
88+
type UserInfo = Record<string, string>;
89+
90+
const maxConcurrentDbRequests = 32;
91+
const dbAccessSemaphore = new ZeroBackpressureSemaphore<UserInfo>(maxConcurrentDbRequests);
92+
93+
app.get('/user/', async (req, res) => {
94+
// Define the sub-prodecure.
95+
const fetchUserInfo: SemaphoreJob<UserInfo> = async (): Promise<UserInfo> => {
96+
const userInfo: UserInfo = await usersDbClient.get(req.userID);
97+
return userInfo;
98+
}
99+
100+
// Execute the sub-procedure in a controlled manner.
101+
try {
102+
const userInfo: UserInfo = await dbAccessSemaphore.waitForCompletion(fetchUserInfo);
103+
res.status(HTTP_OK_CODE).send(userInfo);
104+
} catch (err) {
105+
// err was thrown by the fetchUserInfo job.
106+
logger.error(`Failed fetching user info for userID ${req.userID} with error: ${err.message}`);
107+
res.status(HTTP_ERROR_CODE);
108+
}
109+
});
110+
```
111+
112112
## Graceful Termination
113113

114114
The `waitTillAllExecutingJobsAreSettled` method is essential for scenarios where it is necessary to wait for all ongoing jobs to finish, such as logging a success message or executing subsequent logic.

package-lock.json

+15-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zero-backpressure-semaphore-typescript",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "A classic semaphore with modern API, inspired by the RAII idiom, offering backpressure control for enhanced efficiency",
55
"repository": {
66
"type": "git",
@@ -35,9 +35,9 @@
3535
"devDependencies": {
3636
"@types/jest": "^29.5.12",
3737
"jest": "^29.7.0",
38-
"ts-jest": "^29.1.2",
38+
"ts-jest": "^29.1.5",
3939
"ts-node": "^10.9.2",
40-
"typescript": "^5.4.5"
40+
"typescript": "^5.5.2"
4141
},
4242
"types": "./dist/ZeroBackpressureSemaphore.d.ts",
4343
"main": "./dist/ZeroBackpressureSemaphore.js",

0 commit comments

Comments
 (0)