Skip to content

Commit 977019a

Browse files
committed
major: node 8.9.0+ & semaphore feature
BREAKING CHANGE: starts using native async/await requiring node >= 8.9.0 * feat: semaphore. Leverage existing distributed lock to sequentially grant passage to branches of code * chore: use semantic-release for automatic deploys
1 parent cf76af3 commit 977019a

File tree

13 files changed

+3795
-1685
lines changed

13 files changed

+3795
-1685
lines changed

.babelrc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
{
22
"plugins": [
33
"transform-strict-mode"
4-
]
4+
],
5+
"env": {
6+
"test": {
7+
"plugins": [
8+
"istanbul"
9+
]
10+
}
11+
}
512
}

.mdeprc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"nycCoverage": false,
3+
"test_framework": "jest --coverage --coverageDirectory <coverageDirectory> --forceExit",
4+
"tests": "__tests__/*.js",
5+
"docker_compose": "__tests__/docker-compose.yml"
6+
}

.npmignore

Lines changed: 0 additions & 32 deletions
This file was deleted.

.nycrc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"include": [
3+
"src/**/*.js",
4+
"vendor/**/*.js"
5+
],
6+
"exclude": [
7+
"src/**/*.spec.js"
8+
],
9+
"require": [
10+
"babel-register"
11+
],
12+
"sourceMap": false,
13+
"instrument": false,
14+
"cache": true,
15+
"reporter": [
16+
"lcov",
17+
"json",
18+
"text-summary"
19+
]
20+
}

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ const CallbackQueue = require('dlock');
2424
// one called `redis` and the other `pubsub`. They must be different clients
2525
// technically they can even connect to different redis instances machines,
2626
// since they are used for 2 separate tasks
27+
```
28+
29+
### Sample configuration
2730

31+
```js
2832
const opts = {
2933
client: redis, // lock acquisition, can be shared with the rest of the app
3034
pubsub: pubsub, // pubsub, please do not share unless you know what you are doing
@@ -39,7 +43,14 @@ const opts = {
3943
};
4044

4145
const callbackQueue = new CallbackQueue(opts);
46+
```
47+
48+
### In-flight Request Caching
4249

50+
Perform only 1 request and fan-out results via redis pubsub on the network, so that
51+
we never perform more than 1 requests to the same resource in parallel
52+
53+
```js
4354
/**
4455
* Method push
4556
* Accepts following arguments:
@@ -81,7 +92,13 @@ function onJobCompleted(err, ...args) {
8192
// prints 2
8293
console.log(args[0]);
8394
}
95+
```
96+
97+
### Distributed Resource Locking
98+
99+
Allows to acquire lock across multiple processes with redis based lock
84100

101+
```js
85102
/**
86103
* Method `once` - means there can only be 1 concurrent task
87104
* and callers will be rejected if they can't acquire lock
@@ -100,7 +117,16 @@ callbackQueue
100117
.catch(err => {
101118
// lock could not be acquire
102119
})
120+
```
121+
122+
### Distributed Locking on Multiple Keys
103123

124+
A little more complex lock, which ensures that we can acquire all locks from a list.
125+
When at least one lock is not acquired - we can't proceed further.
126+
This can be helpful in cases when partial resource can be altered in a separate action
127+
and side-effect from such event would affect further actions from a multi lock.
128+
129+
```js
104130
/**
105131
* Method `multi` - similar to once, except that it expects to hold
106132
* multiple locks concurrently. This is useful when you want to perform non-atomic
@@ -135,5 +161,27 @@ callbackQueue
135161
// unexpected error - perhaps redis was offline
136162
// or timed out. ioredis-created errors would be defined here
137163
});
164+
```
165+
166+
### Semaphore
167+
168+
Ensures that all requests are processed one by one. It doesn't guarantee FIFO, but ensures that
169+
not more than 1 request runs at any given time.
138170

171+
```js
172+
const Promise = require('bluebird');
173+
const semaphore = callbackQueue.semaphore('job:id');
174+
175+
// option 1 - use disposer that will automatically call semaphore.leave
176+
Promise.using(semaphore.take(), () => {
177+
// do some work, return promise
178+
});
179+
180+
// option 2
181+
await semaphore.take();
182+
try {
183+
// perform some async work and ensure we call leave afterwards
184+
} finally {
185+
semaphore.leave();
186+
}
139187
```

__tests__/.eslintrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"env": {
3+
"jest": true
4+
}
5+
}

__tests__/docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
version: '2'
2+
3+
services:
4+
redis:
5+
image: redis:3.2.9-alpine
6+
container_name: redis
7+
hostname: redis
8+
expose:
9+
- 6379
10+
11+
tester:
12+
image: makeomatic/node:9.3.0-tester
13+
container_name: tester
14+
hostname: tester
15+
links:
16+
- redis
17+
working_dir: /src
18+
volumes:
19+
- ${PWD}:/src
20+
environment:
21+
NODE_ENV: "test"
22+
command: tail -f /dev/null

0 commit comments

Comments
 (0)