dflockd-client 1.8.3 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -85,8 +85,9 @@ declare function stats(options?: {
85
85
  port?: number;
86
86
  tls?: tls.ConnectionOptions;
87
87
  auth?: string;
88
+ connectTimeoutMs?: number;
88
89
  }): Promise<Stats>;
89
- interface DistributedLockOptions {
90
+ interface BaseOptions {
90
91
  key: string;
91
92
  acquireTimeoutS?: number;
92
93
  leaseTtlS?: number;
@@ -100,83 +101,22 @@ interface DistributedLockOptions {
100
101
  tls?: tls.ConnectionOptions;
101
102
  auth?: string;
102
103
  onLockLost?: (key: string, token: string) => void;
103
- }
104
- declare class DistributedLock {
105
- readonly key: string;
106
- readonly acquireTimeoutS: number;
107
- readonly leaseTtlS: number | undefined;
108
- readonly servers: Array<[string, number]>;
109
- readonly shardingStrategy: ShardingStrategy;
110
- readonly renewRatio: number;
111
- readonly tls: tls.ConnectionOptions | undefined;
112
- readonly auth: string | undefined;
113
- readonly onLockLost: ((key: string, token: string) => void) | undefined;
114
- token: string | null;
115
- lease: number;
116
- private sock;
117
- private renewTimer;
118
- private closed;
119
- constructor(opts: DistributedLockOptions);
120
- private pickServer;
121
- /**
122
- * Acquire the lock. Returns `true` on success, `false` on timeout.
123
- * @param opts.force - If `true`, silently close any existing connection before acquiring. Defaults to `false`, which throws if already connected.
124
- */
125
- acquire(opts?: {
126
- force?: boolean;
127
- }): Promise<boolean>;
128
- /** Release the lock and close the connection. */
129
- release(): Promise<void>;
130
- /**
131
- * Two-phase step 1: connect and join the FIFO queue.
132
- * Returns `"acquired"` (fast-path, lock is already held) or `"queued"`.
133
- * If acquired immediately, the renew loop starts automatically.
134
- * @param opts.force - If `true`, silently close any existing connection before enqueuing. Defaults to `false`, which throws if already connected.
135
- */
136
- enqueue(opts?: {
137
- force?: boolean;
138
- }): Promise<"acquired" | "queued">;
139
- /**
140
- * Two-phase step 2: block until the lock is granted.
141
- * Returns `true` if granted, `false` on timeout.
142
- * If already acquired during `enqueue()`, returns `true` immediately.
143
- */
144
- wait(timeoutS?: number): Promise<boolean>;
104
+ /** TCP connect timeout in milliseconds. Undefined means no timeout. */
105
+ connectTimeoutMs?: number;
145
106
  /**
146
- * Run `fn` while holding the lock, then release automatically.
147
- *
148
- * ```ts
149
- * const lock = new DistributedLock({ key: "my-resource" });
150
- * await lock.withLock(async () => {
151
- * // critical section
152
- * });
153
- * ```
107
+ * Socket idle timeout in milliseconds. If no data is received within this
108
+ * period, the socket emits a 'timeout' event and is destroyed, causing any
109
+ * pending `readline` to reject. Undefined means no timeout.
154
110
  */
155
- withLock<T>(fn: () => T | Promise<T>): Promise<T>;
156
- /** Close the underlying socket (idempotent). */
157
- close(): void;
158
- private startRenew;
159
- private stopRenew;
111
+ socketTimeoutMs?: number;
160
112
  }
161
- interface DistributedSemaphoreOptions {
162
- key: string;
113
+ interface DistributedLockOptions extends BaseOptions {
114
+ }
115
+ interface DistributedSemaphoreOptions extends BaseOptions {
163
116
  limit: number;
164
- acquireTimeoutS?: number;
165
- leaseTtlS?: number;
166
- /** @deprecated Use `servers` instead. */
167
- host?: string;
168
- /** @deprecated Use `servers` instead. */
169
- port?: number;
170
- servers?: Array<[host: string, port: number]>;
171
- shardingStrategy?: ShardingStrategy;
172
- renewRatio?: number;
173
- tls?: tls.ConnectionOptions;
174
- auth?: string;
175
- onLockLost?: (key: string, token: string) => void;
176
117
  }
177
- declare class DistributedSemaphore {
118
+ declare abstract class DistributedPrimitive {
178
119
  readonly key: string;
179
- readonly limit: number;
180
120
  readonly acquireTimeoutS: number;
181
121
  readonly leaseTtlS: number | undefined;
182
122
  readonly servers: Array<[string, number]>;
@@ -185,46 +125,80 @@ declare class DistributedSemaphore {
185
125
  readonly tls: tls.ConnectionOptions | undefined;
186
126
  readonly auth: string | undefined;
187
127
  readonly onLockLost: ((key: string, token: string) => void) | undefined;
128
+ readonly connectTimeoutMs: number | undefined;
129
+ readonly socketTimeoutMs: number | undefined;
188
130
  token: string | null;
189
131
  lease: number;
190
132
  private sock;
191
133
  private renewTimer;
134
+ private renewInFlight;
192
135
  private closed;
193
- constructor(opts: DistributedSemaphoreOptions);
136
+ constructor(opts: BaseOptions);
137
+ protected abstract doAcquire(sock: net.Socket): Promise<{
138
+ token: string;
139
+ lease: number;
140
+ }>;
141
+ protected abstract doEnqueue(sock: net.Socket): Promise<{
142
+ status: "acquired" | "queued";
143
+ token: string | null;
144
+ lease: number | null;
145
+ }>;
146
+ protected abstract doWait(sock: net.Socket, timeoutS: number): Promise<{
147
+ token: string;
148
+ lease: number;
149
+ }>;
150
+ protected abstract doRelease(sock: net.Socket, token: string): Promise<void>;
151
+ protected abstract doRenew(sock: net.Socket, token: string): Promise<number>;
152
+ private openConnection;
153
+ /**
154
+ * Suspend or restore the socket idle timeout. Only has effect when
155
+ * `socketTimeoutMs` was set at construction time and a listener was
156
+ * registered in `openConnection`.
157
+ */
158
+ private suspendSocketTimeout;
159
+ private restoreSocketTimeout;
194
160
  private pickServer;
195
161
  /**
196
- * Acquire a semaphore slot. Returns `true` on success, `false` on timeout.
197
- * @param opts.force - If `true`, silently close any existing connection before acquiring. Defaults to `false`, which throws if already connected.
162
+ * Acquire the lock / semaphore slot.
163
+ * Returns `true` on success, `false` on timeout.
164
+ * @param opts.force - If `true`, silently close any existing connection
165
+ * before acquiring. Defaults to `false`, which throws if already connected.
198
166
  */
199
167
  acquire(opts?: {
200
168
  force?: boolean;
201
169
  }): Promise<boolean>;
202
- /** Release the semaphore slot and close the connection. */
170
+ /**
171
+ * Release the lock / semaphore slot and close the connection.
172
+ *
173
+ * Throws `LockError` if the instance is already closed (e.g. after a
174
+ * previous `release()` or `close()` call).
175
+ *
176
+ * The server-side release itself is best-effort: if the underlying
177
+ * connection is already dead the protocol-level release error is silently
178
+ * ignored so that the method doesn't throw on transient network failures.
179
+ */
203
180
  release(): Promise<void>;
204
181
  /**
205
182
  * Two-phase step 1: connect and join the FIFO queue.
206
- * Returns `"acquired"` (fast-path, slot granted immediately) or `"queued"`.
183
+ * Returns `"acquired"` (fast-path) or `"queued"`.
207
184
  * If acquired immediately, the renew loop starts automatically.
208
- * @param opts.force - If `true`, silently close any existing connection before enqueuing. Defaults to `false`, which throws if already connected.
185
+ * @param opts.force - If `true`, silently close any existing connection
186
+ * before enqueuing. Defaults to `false`, which throws if already connected.
209
187
  */
210
188
  enqueue(opts?: {
211
189
  force?: boolean;
212
190
  }): Promise<"acquired" | "queued">;
213
191
  /**
214
- * Two-phase step 2: block until a semaphore slot is granted.
192
+ * Two-phase step 2: block until the lock / slot is granted.
215
193
  * Returns `true` if granted, `false` on timeout.
216
194
  * If already acquired during `enqueue()`, returns `true` immediately.
217
195
  */
218
196
  wait(timeoutS?: number): Promise<boolean>;
219
197
  /**
220
- * Run `fn` while holding a semaphore slot, then release automatically.
198
+ * Run `fn` while holding the lock / slot, then release automatically.
221
199
  *
222
- * ```ts
223
- * const sem = new DistributedSemaphore({ key: "my-resource", limit: 5 });
224
- * await sem.withLock(async () => {
225
- * // critical section (up to 5 concurrent holders)
226
- * });
227
- * ```
200
+ * If `fn()` throws, its error is always preserved — a concurrent
201
+ * release failure will not mask it.
228
202
  */
229
203
  withLock<T>(fn: () => T | Promise<T>): Promise<T>;
230
204
  /** Close the underlying socket (idempotent). */
@@ -232,5 +206,42 @@ declare class DistributedSemaphore {
232
206
  private startRenew;
233
207
  private stopRenew;
234
208
  }
209
+ declare class DistributedLock extends DistributedPrimitive {
210
+ constructor(opts: DistributedLockOptions);
211
+ protected doAcquire(sock: net.Socket): Promise<{
212
+ token: string;
213
+ lease: number;
214
+ }>;
215
+ protected doEnqueue(sock: net.Socket): Promise<{
216
+ status: "acquired" | "queued";
217
+ token: string | null;
218
+ lease: number | null;
219
+ }>;
220
+ protected doWait(sock: net.Socket, timeoutS: number): Promise<{
221
+ token: string;
222
+ lease: number;
223
+ }>;
224
+ protected doRelease(sock: net.Socket, token: string): Promise<void>;
225
+ protected doRenew(sock: net.Socket, token: string): Promise<number>;
226
+ }
227
+ declare class DistributedSemaphore extends DistributedPrimitive {
228
+ readonly limit: number;
229
+ constructor(opts: DistributedSemaphoreOptions);
230
+ protected doAcquire(sock: net.Socket): Promise<{
231
+ token: string;
232
+ lease: number;
233
+ }>;
234
+ protected doEnqueue(sock: net.Socket): Promise<{
235
+ status: "acquired" | "queued";
236
+ token: string | null;
237
+ lease: number | null;
238
+ }>;
239
+ protected doWait(sock: net.Socket, timeoutS: number): Promise<{
240
+ token: string;
241
+ lease: number;
242
+ }>;
243
+ protected doRelease(sock: net.Socket, token: string): Promise<void>;
244
+ protected doRenew(sock: net.Socket, token: string): Promise<number>;
245
+ }
235
246
 
236
247
  export { AcquireTimeoutError, AuthError, DistributedLock, type DistributedLockOptions, DistributedSemaphore, type DistributedSemaphoreOptions, LockError, type ShardingStrategy, type Stats, type StatsIdleLock, type StatsIdleSemaphore, type StatsLock, type StatsSemaphore, acquire, enqueue, release, renew, semAcquire, semEnqueue, semRelease, semRenew, semWaitForLock, stableHashShard, stats, waitForLock };