Skip to content

Commit 0669a29

Browse files
committed
refactor: refactorLock new api
1 parent b94065c commit 0669a29

8 files changed

Lines changed: 73 additions & 16 deletions

File tree

docs/content/docs/api.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,11 @@ First argument is the lock key. Second argument is optional and is the lock expi
132132

133133
### `restoreLock`
134134

135-
Restore a lock with a given owner. Useful when sharing a lock between multiple processes. See [Sharing a lock between multiple processes](./usage.md#sharing-a-lock-between-multiple-processes) for more details.
135+
Restore a lock. Useful when sharing a lock between multiple processes. See [Sharing a lock between multiple processes](./usage.md#sharing-a-lock-between-multiple-processes) for more details.
136136

137137
```ts
138-
const lock = verrou.restoreLock('key', 'owner')
138+
const lock1 = verrou.createLock('key', 'owner')
139+
const lock2 = verrou.restoreLock(lock1.serialize())
139140
```
140141

141142
### `disconnect`

docs/content/docs/usage.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ router.get('/process-payment', async (req, res) => {
165165
await lock.acquire()
166166

167167
myQueue.dispatch('process-payment', {
168-
paymentId: 123,
169-
lockOwner: lock.getOwner()
168+
paymentId: 123,
169+
lock: lock.serialize()
170170
})
171171
})
172172
```
@@ -177,9 +177,9 @@ So we dispatch a message to our queue with the lock owner. Now let's see how we
177177
// title: worker.ts
178178
import { verrou } from './verrou.js'
179179

180-
myQueue.on('process-payment', async ({ paymentId, lockOwner }) => {
180+
myQueue.on('process-payment', async ({ paymentId, lock }) => {
181181
// First we **restore** the lock with the lock owner
182-
const lock = verrou.restoreLock('my-resource', lockOwner)
182+
const lock = verrou.restoreLock(lock)
183183

184184
processPayment(paymentId)
185185

@@ -188,7 +188,7 @@ myQueue.on('process-payment', async ({ paymentId, lockOwner }) => {
188188
})
189189
```
190190

191-
As you can see, we can restore a lock by calling the `restoreLock` method and passing the lock owner. This will create a new `Lock` instance with the same resource and owner. Then we can release it.
191+
As you can see, we can restore a lock by calling the `restoreLock` method and passing the serialized lock. This will create a new `Lock` instance with the same resource and owner. Then we can release it.
192192

193193
Note that you can also use `lock.forceRelease()` to release a lock, no matter the owner.
194194

packages/verrou/src/lock.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import { InvalidArgumentsException } from '@poppinss/utils'
33

44
import { E_LOCK_TIMEOUT } from './errors.js'
55
import { resolveDuration } from './helpers.js'
6-
import type { Duration, LockAcquireOptions, LockFactoryConfig, LockStore } from './types/main.js'
6+
import type {
7+
Duration,
8+
LockAcquireOptions,
9+
LockFactoryConfig,
10+
LockStore,
11+
SerializedLock,
12+
} from './types/main.js'
713

814
export class Lock {
915
#key: string
@@ -19,11 +25,12 @@ export class Lock {
1925
config: LockFactoryConfig,
2026
owner?: string,
2127
ttl?: number | null,
28+
expirationTime?: number | null,
2229
) {
2330
this.#key = key
2431
this.#config = config
2532
this.#lockStore = lockStore
26-
this.#expirationTime = null
33+
this.#expirationTime = expirationTime ?? null
2734
this.#owner = owner ?? this.#generateOwner()
2835
this.#ttl = ttl ?? null
2936
}
@@ -42,6 +49,18 @@ export class Lock {
4249
return this.#owner
4350
}
4451

52+
/**
53+
* Serialize the lock
54+
*/
55+
serialize(): SerializedLock {
56+
return {
57+
key: this.#key,
58+
owner: this.#owner,
59+
ttl: this.#ttl,
60+
expirationTime: this.#expirationTime,
61+
}
62+
}
63+
4564
/**
4665
* Acquire the lock
4766
*/

packages/verrou/src/lock_factory.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { noopLogger } from 'typescript-log'
22

33
import { Lock } from './lock.js'
44
import { resolveDuration } from './helpers.js'
5-
import type { Duration, LockFactoryConfig, LockFactoryOptions, LockStore } from './types/main.js'
5+
import type {
6+
Duration,
7+
LockFactoryConfig,
8+
LockFactoryOptions,
9+
LockStore,
10+
SerializedLock,
11+
} from './types/main.js'
612

713
export class LockFactory {
814
/**
@@ -37,8 +43,8 @@ export class LockFactory {
3743
* if you want to release a lock from a different process than the one
3844
* that acquired it.
3945
*/
40-
restoreLock(name: string, owner: string, ttl: Duration = LockFactory.#kDefaultTtl) {
41-
return new Lock(name, this.store, this.#config, owner, resolveDuration(ttl))
46+
restoreLock(lock: SerializedLock) {
47+
return new Lock(lock.key, this.store, this.#config, lock.owner, lock.ttl, lock.expirationTime)
4248
}
4349

4450
/**

packages/verrou/src/types/main.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ export type StoreFactory = {
1616
driver: { factory: () => LockStore }
1717
}
1818

19+
export interface SerializedLock {
20+
key: string
21+
owner: string
22+
ttl: number | null
23+
expirationTime: number | null
24+
}
25+
1926
export interface RetryConfig {
2027
/**
2128
* The number of times to retry the operation before giving up.

packages/verrou/src/verrou.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { noopLogger, type Logger } from 'typescript-log'
22

33
import { LockFactory } from './lock_factory.js'
4-
import type { Duration, StoreFactory } from './types/main.js'
4+
import type { Duration, SerializedLock, StoreFactory } from './types/main.js'
55

66
/**
77
* Verrou is the main class of the library. It is used to create locks
@@ -67,8 +67,8 @@ export class Verrou<KnownStores extends Record<string, StoreFactory>> {
6767
* if you want to release a lock from a different process than the one
6868
* that acquired it.
6969
*/
70-
restoreLock(name: string, owner: string, ttl?: Duration) {
71-
return this.use(this.#defaultStoreName).restoreLock(name, owner, ttl)
70+
restoreLock(lock: SerializedLock) {
71+
return this.use(this.#defaultStoreName).restoreLock(lock)
7272
}
7373

7474
/**

packages/verrou/test_helpers/driver_test_suite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export function registerStoreTestSuite<T extends { new (options: any): LockStore
193193
await lock.acquire()
194194

195195
const provider2 = new LockFactory(storeInstance)
196-
const lock2 = provider2.restoreLock('foo', lock.getOwner())
196+
const lock2 = provider2.restoreLock(lock.serialize())
197197

198198
assert.isTrue(await lock2.isLocked())
199199
await lock2.release()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { test } from '@japa/runner'
2+
import { setTimeout } from 'node:timers/promises'
3+
4+
import { LockFactory } from '../src/lock_factory.js'
5+
import { MemoryStore } from '../src/drivers/memory.js'
6+
7+
test.group('Lock Factory', () => {
8+
test('restoreLock should preserve expiration time', async ({ assert }) => {
9+
const store = new MemoryStore()
10+
const lockFactory = new LockFactory(store)
11+
12+
const lock = lockFactory.createLock('foo', '1s')
13+
14+
await lock.acquire()
15+
16+
await setTimeout(100)
17+
18+
const serializedLock = lock.serialize()
19+
const restoredLock = lockFactory.restoreLock(serializedLock)
20+
21+
assert.closeTo(restoredLock.getRemainingTime()!, 900, 100)
22+
assert.deepEqual(restoredLock.getRemainingTime(), lock.getRemainingTime())
23+
})
24+
})

0 commit comments

Comments
 (0)