UNPKG

7.54 kBMarkdownView Raw
1[![npm version](https://badge.fury.io/js/redlock.svg)](https://www.npmjs.com/package/redlock)
2[![Build Status](https://travis-ci.org/mike-marcacci/node-redlock.svg)](https://travis-ci.org/mike-marcacci/node-redlock)
3[![Coverage Status](https://coveralls.io/repos/mike-marcacci/node-redlock/badge.svg)](https://coveralls.io/r/mike-marcacci/node-redlock)
4
5Redlock
6=======
7This is a node.js implementation of the [redlock](http://redis.io/topics/distlock) algorithm for distributed redis locks. It provides strong guarantees in both single-redis and multi-redis environments, and provides fault tolerance through use of multiple independent redis instances or clusters.
8
9###High-Availability Recommendations
10- Use at least 3 independent servers or clusters
11- Use an odd number of independent redis ***servers*** for most installations
12- Use an odd number of independent redis ***clusters*** for massive installations
13- When possible, distribute redis nodes across different physical machines
14
15
16Installation
17------------
18```bash
19npm install --save redlock
20```
21
22Configuration
23-------------
24Redlock can use [node redis](https://github.com/mranney/node_redis), [ioredis](https://github.com/luin/ioredis) or any other compatible redis library to keep its client connections.
25
26A redlock object is instantiated with an array of at least one redis client and an optional `options` object. Properties of the Redlock object should NOT be changed after it is firstused, as doing so could have unintended consequences for live locks.
27
28```js
29var client1 = require('redis').createClient(6379, 'redis1.example.com');
30var client2 = require('redis').createClient(6379, 'redis2.example.com');
31var client3 = require('redis').createClient(6379, 'redis3.example.com');
32var Redlock = require('redlock');
33
34var redlock = new Redlock(
35 // you should have one client for each redis node
36 // in your cluster
37 [client1, client2, client3],
38 {
39 // the expected clock drift; for more details
40 // see http://redis.io/topics/distlock
41 driftFactor: 0.01,
42
43 // the max number of times Redlock will attempt
44 // to lock a resource before erroring
45 retryCount: 3,
46
47 // the time in ms between attempts
48 retryDelay: 200
49 }
50);
51```
52
53
54Error Handling
55--------------
56
57Because redlock is designed for high availability, it does not care if a minority of redis instances/clusters fail at an operation. If you want to write logs or take another action when a redis client fails, you can listen for the `clientError` event:
58
59```js
60
61// ...
62
63redlock.on('clientError', function(err) {
64 console.error('A redis error has occurred:', err);
65});
66
67// ...
68
69```
70
71
72Usage (promise style)
73---------------------
74
75
76###Locking & Unocking
77
78```js
79
80// the string identifier for the resource you want to lock
81var resource = 'locks:account:322456';
82
83// the maximum amount of time you want the resource locked,
84// keeping in mind that you can extend the lock up until
85// the point when it expires
86var ttl = 1000;
87
88redlock.lock(resource, ttl).then(function(lock) {
89
90 // ...do something here...
91
92 // unlock your resource when you are done
93 return lock.unlock()
94 .catch(function(err) {
95 // we weren't able to reach redis; your lock will eventually
96 // expire, but you probably want to log this error
97 console.error(err);
98 });
99});
100
101```
102
103
104###Locking and Extending
105
106```js
107redlock.lock('locks:account:322456', 1000).then(function(lock) {
108
109 // ...do something here...
110
111 // if you need more time, you can continue to extend
112 // the lock as long as you never let it expire
113 return lock.extend(1000).then(function(lock){
114
115 // ...do something here...
116
117 // unlock your resource when you are done
118 return lock.unlock()
119 .catch(function(err) {
120 // we weren't able to reach redis; your lock will eventually
121 // expire, but you probably want to log this error
122 console.error(err);
123 });
124 });
125});
126
127```
128
129
130Usage (disposer style)
131----------------------
132
133
134###Locking & Unocking
135
136```js
137var using = require('bluebird').using;
138
139// the string identifier for the resource you want to lock
140var resource = 'locks:account:322456';
141
142// the maximum amount of time you want the resource locked,
143// keeping in mind that you can extend the lock up until
144// the point when it expires
145var ttl = 1000;
146
147// if we weren't able to reach redis, your lock will eventually
148// expire, but you probably want to do something like log that
149// an error occurred; if you don't pass a handler, this error
150// will be ignored
151function unlockErrorHandler(err) {
152 console.error(err);
153}
154
155using(redlock.disposer(resource, ttl, unlockErrorHandler), function(lock) {
156
157 // ...do something here...
158
159}); // <-- unlock is automatically handled by bluebird
160
161```
162
163
164###Locking and Extending
165
166```js
167using(redlock.disposer('locks:account:322456', 1000, unlockErrorHandler), function(lock) {
168
169 // ...do something here...
170
171 // if you need more time, you can continue to extend
172 // the lock until it expires
173 return lock.extend(1000).then(function(extended){
174
175 // Note that redlock modifies the original lock,
176 // so the vars `lock` and `extended` point to the
177 // exact same object
178
179 // ...do something here...
180
181 });
182}); // <-- unlock is automatically handled by bluebird
183
184```
185
186
187Usage (callback style)
188----------------------
189
190
191###Locking & Unocking
192
193```js
194
195// the string identifier for the resource you want to lock
196var resource = 'locks:account:322456';
197
198// the maximum amount of time you want the resource locked,
199// keeping in mind that you can extend the lock up until
200// the point when it expires
201var ttl = 1000;
202
203redlock.lock(resource, ttl, function(err, lock) {
204
205 // we failed to lock the resource
206 if(err) {
207 // ...
208 }
209
210 // we have the lock
211 else {
212
213
214 // ...do something here...
215
216
217 // unlock your resource when you are done
218 lock.unlock(function(err) {
219 // we weren't able to reach redis; your lock will eventually
220 // expire, but you probably want to log this error
221 console.error(err);
222 });
223 }
224});
225
226```
227
228
229###Locking and Extending
230
231```js
232redlock.lock('locks:account:322456', 1000, function(err, lock) {
233
234 // we failed to lock the resource
235 if(err) {
236 // ...
237 }
238
239 // we have the lock
240 else {
241
242
243 // ...do something here...
244
245
246 // if you need more time, you can continue to extend
247 // the lock until it expires
248 lock.extend(1000, function(err, lock){
249
250 // we failed to extend the lock on the resource
251 if(err) {
252 // ...
253 }
254
255
256 // ...do something here...
257
258
259 // unlock your resource when you are done
260 lock.unlock();
261 }
262 }
263});
264
265```
266
267API Docs
268--------
269
270###`Redlock.lock(resource, ttl, ?callback)`
271- `resource (string)` resource to be locked
272- `ttl (number)` time in ms until the lock expires
273- `callback (function)` callback returning:
274 - `err (Error)`
275 - `lock (Lock)`
276
277
278###`Redlock.unlock(lock, ?callback)`
279- `lock (Lock)` lock to be released
280- `callback (function)` callback returning:
281 - `err (Error)`
282
283
284###`Redlock.extend(lock, ttl, ?callback)`
285- `lock (Lock)` lock to be extended
286- `ttl (number)` time in ms to extend the lock's expiration
287- `callback (function)` callback returning:
288 - `err (Error)`
289 - `lock (Lock)`
290
291
292###`Redlock.disposer(resource, ttl, ?unlockErrorHandler)`
293- `resource (string)` resource to be locked
294- `ttl (number)` time in ms to extend the lock's expiration
295- `callback (function)` error handler called with:
296 - `err (Error)`
297
298
299###`Lock.unlock(?callback)`
300- `callback (function)` callback returning:
301 - `err (Error)`
302
303
304###`Lock.extend(ttl, ?callback)`
305- `ttl (number)` time in ms to extend the lock's expiration
306- `callback (function)` callback returning:
307 - `err (Error)`
308 - `lock (Lock)`
309