UNPKG

8.9 kBTypeScriptView Raw
1/// <reference types="node" />
2/// <reference types="bluebird" />
3import * as Promise from 'bluebird';
4import { EventEmitter } from 'events';
5import { Locator } from 'locators';
6import * as zk from 'node-zookeeper-client';
7/**
8 * Error thrown by locking action when blocking wait for lock reaches a timeout period
9 */
10export declare class ZookeeperLockTimeoutError extends Error {
11 lockPath: string;
12 timeout?: number;
13 constructor(message: string, path: string, timeout?: number);
14}
15/**
16 * Error thrown by locking action when config.failImmediate == true when a lock is already locked
17 */
18export declare class ZookeeperLockAlreadyLockedError extends Error {
19 lockPath: string;
20 constructor(message: string, path: string);
21}
22export declare class ZookeeperLockConfiguration {
23 /**
24 * locators (https://github.com/metamx/locators) compatible zookeeper server locator
25 */
26 serverLocator?: Locator;
27 /**
28 * prefix which will be placed in front of all locks created from this lock
29 */
30 pathPrefix?: string;
31 /**
32 * zookeeper client session timeout
33 */
34 sessionTimeout?: number;
35 /**
36 * milliseconds, dual function parameter, functioning both as zookeeper lock 'reconnect' delay
37 * as well as internal zookeeper client spinDelay
38 */
39 spinDelay?: number;
40 /**
41 * milliseconds, dual function parameter, functioning both as zookeeper lock 'reconnect' limit
42 * as well as internal zookeeper client retries
43 */
44 retries?: number;
45 /**
46 * when true, all calls to unlock will destroy the lock, detaching all event listeners, in addition
47 * to the normal disconnect. defaults to true to reduce the chance of leaky usage
48 */
49 autoDestroyOnUnlock?: boolean;
50 /**
51 * when true, if the lock is not obtainable immediately, fail with a ZookeeperLockAlreadyLockedError and
52 * disconnect or destroy depending on autoDestroyOnUnlock the lock
53 */
54 failImmediate?: boolean;
55 /**
56 * allowed number of maximum concurrent holders of a lock, defaults to 1 for traditional lock-like
57 * behavior. Note that this value is NOT enforced, it's merely an agreement that all lock clients
58 * agree to follow when working with this lock path, but allows using the zookeeper lock for additional
59 * cluster orchestration roles like controlling the maximum number of concurrent workers
60 */
61 maxConcurrentHolders?: number;
62 /**
63 * if set to true, set a timeout defaulting to 10 seconds to give status updates on the lock while it
64 * is connected to zookeeper, used to help debug working with the locks to detect leaks or what not,
65 * visible by launching the app with the environment variable NODE_DEBUG=zk-lock set
66 */
67 enableTraceLog?: boolean;
68 /**
69 * milliseconds, the rate at which debug trace logs are emitted when enableTraceLog is set to true
70 */
71 traceLogRefresh?: number;
72 /**
73 * milliseconds, the quiet period after a lock is connected until the traceLog will begin reporting
74 * long held locks and suspected connection leaks in a more verbose manner
75 */
76 traceLogQuietPeriod?: number;
77}
78export declare class ZookeeperLock extends EventEmitter {
79 static Signals: {
80 LOST: string;
81 TIMEOUT: string;
82 };
83 static States: {
84 ALREADY_LOCKED: string;
85 DESTROYED: string;
86 ERROR: string;
87 LOCKED: string;
88 LOCKING: string;
89 LOST: string;
90 TIMEOUT: string;
91 UNLOCKED: string;
92 UNLOCKING: string;
93 };
94 private static config;
95 path: string;
96 key: string;
97 client: zk.Client;
98 state: string;
99 private config;
100 private retryCount;
101 private timeout;
102 private created;
103 /**
104 * set static config to use by static helper methods
105 * @param config
106 */
107 static initialize: (config: any) => void;
108 /**
109 * create a new lock using the static stored config
110 * @returns {ZookeeperLock}
111 */
112 static lockFactory: () => ZookeeperLock;
113 /**
114 * create a new lock and lock it using the static stored config, with optional timeout
115 * @param key
116 * @param timeout
117 * @returns {Promise<ZookeeperLock>}
118 */
119 static lock: (key: string, timeout?: number) => Promise<ZookeeperLock>;
120 /**
121 * check if a lock exists for a path using the static config
122 * @param key
123 * @returns {Promise<boolean>}
124 */
125 static checkLock: (key: string) => Promise<boolean>;
126 /**
127 * get the numeric part of the lock key
128 * @param path
129 * @returns {number}
130 */
131 private static getSequenceNumber;
132 /**
133 * create a new zk lock
134 * @param config
135 */
136 constructor(config: ZookeeperLockConfiguration);
137 /**
138 * connect underlying zookeeper client, with optional delay
139 * @param [delay=0]
140 * @returns {Promise<any>}
141 */
142 connect: (delay?: number) => Promise<any>;
143 /**
144 * disconnect zookeeper client, and remove all event listeners from it
145 * @returns {Promise<any>}
146 */
147 disconnect: () => Promise<any>;
148 /**
149 * destroy the lock, disconnect and remove all listeners from the 'signal' event emitter
150 * @returns {Promise<any>}
151 */
152 destroy: () => Promise<boolean>;
153 /**
154 * unlock a lock, removing the key from zookeeper, and disconnecting
155 * the zk client and all event listeners. By default this also destroys
156 * the lock and removes event listeners on the locks 'signals' event
157 * @param [destroy=true] - remove listeners from lock in addition
158 * to disconnecting zk client on completion, defaults to true
159 * @returns {Promise<any>}
160 */
161 unlock: (destroy?: boolean) => Promise<any>;
162 /**
163 * wait for a lock to become free for a given key and acquire it, with an optional
164 * timeout upon which the lock will fail. if not currently connected to zookeeper,
165 * this will connect, and on timeout, the lock will disconnect from zookeeper
166 * @param key
167 * @param [timeout]
168 * @returns {Promise<any>}
169 */
170 lock: (key: string, timeout?: number) => Promise<any>;
171 /**
172 * check if a lock exists, connecting to zk client if not connected
173 * @param key
174 * @returns {Promise<boolean>}
175 */
176 checkLocked: (key: string) => Promise<boolean>;
177 private changeState(newState);
178 /**
179 * create a zookeeper client which powers the lock, done when creating a new lock
180 * or zk connection expires
181 * @returns {Promise<any>}
182 */
183 private createClient();
184 private traceLog;
185 private connectHelper;
186 private disconnectHelper;
187 /**
188 * internal method to reconnect, wired up to disconnect event of zk client
189 * @returns {Promise<any>}
190 */
191 private reconnect;
192 private lockHelper;
193 /**
194 * make the zk node that will hold the locks if it doens't already exist
195 * @param path
196 * @returns {Promise<any>}
197 */
198 private makeLockDir;
199 /**
200 * create a lock as a ephemeral sequential child node of the supplied path, prefixed with 'lock-',
201 * to state intent to acquire a lock
202 * @param path
203 * @returns {Promise<any>}
204 */
205 private initLock;
206 /**
207 * loop until lock is available or timeout occurs
208 * @param path
209 * @returns {Promise<any>}
210 */
211 private waitForLock;
212 /**
213 * are we on the happy path to continue locking?
214 * @returns {boolean|zk.Client}
215 */
216 private continueLocking;
217 /**
218 * check for states that result from triggers that resolve the external promise chain of the locking process.
219 * The zookeeper client fires all event handlers when it is disconnected, so events like timeouts, already
220 * locked errors, and even unlocking can cause unintended stray events, so we should just bail from these
221 * handlers rather than trigger unintended rejections from race conditions with the intended external rejections
222 * @returns {boolean}
223 */
224 private shouldRejectPromise;
225 /**
226 * helper method that does the grunt of the work of waiting for the lock. This method does 2 things, first
227 * reads the lock path to compare the locks key to the other keys that are children of the path. if this locks
228 * sequence number is the lowest, the lock has been aquired. If not, this method reactively responds to
229 * children changed events from the zk-client for the path we want to aqcuire the lock for, and recurses to
230 * repeat this process until the sequence is the lowest
231 * @param resolve
232 * @param reject
233 * @param path
234 */
235 private waitForLockHelper;
236 /**
237 * method to filter zk node children to contain only those that are prefixed with 'lock-',
238 * which are assumed to be created by this library
239 * @param children
240 * @returns {string[]|T[]}
241 */
242 private filterLocks;
243 private checkedLockedHelper;
244}