File tree Expand file tree Collapse file tree 7 files changed +129
-0
lines changed
Expand file tree Collapse file tree 7 files changed +129
-0
lines changed Original file line number Diff line number Diff line change 5353 "dependencies" : {
5454 "@hashgraph/json-rpc-config-service" : " file:../config-service" ,
5555 "@hashgraph/sdk" : " ^2.63.0" ,
56+ "async-mutex" : " ^0.5.0" ,
5657 "axios" : " ^1.4.0" ,
5758 "axios-retry" : " ^4.5.0" ,
5859 "better-lookup" : " ^1.3.0" ,
Original file line number Diff line number Diff line change @@ -17,3 +17,5 @@ export * from './rateLimiterService/RedisRateLimitStore';
1717export * from './rateLimiterService/rateLimiterService' ;
1818export * from './transactionPoolService/LocalPendingTransactionStorage' ;
1919export * from './transactionPoolService/transactionPoolService' ;
20+ export * from './lockService/LockService' ;
21+ export * from './lockService/LockStrategyFactory' ;
Original file line number Diff line number Diff line change 1+ // SPDX-License-Identifier: Apache-2.0
2+
3+ import { LockStrategy } from '../../types/lock' ;
4+
5+ /**
6+ * Service that manages transaction ordering through distributed locking.
7+ * Uses a strategy pattern to support both local (in-memory) and distributed (Redis) locking.
8+ */
9+ export class LockService {
10+ /**
11+ * The underlying lock strategy implementation (Local or Redis).
12+ */
13+ private readonly strategy : LockStrategy ;
14+
15+ /**
16+ * Creates a new LockService instance.
17+ *
18+ * @param strategy - The lock strategy implementation to use.
19+ */
20+ constructor ( strategy : LockStrategy ) {
21+ this . strategy = strategy ;
22+ }
23+
24+ /**
25+ * Acquires a lock for the specified address.
26+ * Blocks until the lock is available (no timeout on waiting).
27+ *
28+ * @param address - The sender address to acquire the lock for.
29+ * @returns A promise that resolves to a unique session key.
30+ */
31+ async acquireLock ( address : string ) : Promise < string > {
32+ return await this . strategy . acquireLock ( address ) ;
33+ }
34+
35+ /**
36+ * Releases a lock for the specified address.
37+ * Only succeeds if the session key matches the current lock holder.
38+ *
39+ * @param address - The sender address to release the lock for.
40+ * @param sessionKey - The session key obtained during lock acquisition.
41+ */
42+ async releaseLock ( address : string , sessionKey : string ) : Promise < void > {
43+ await this . strategy . releaseLock ( address , sessionKey ) ;
44+ }
45+ }
Original file line number Diff line number Diff line change 1+ // SPDX-License-Identifier: Apache-2.0
2+
3+ import { Logger } from 'pino' ;
4+ import { RedisClientType } from 'redis' ;
5+
6+ import { LockStrategy } from '../../types/lock' ;
7+
8+ /**
9+ * Factory for creating LockStrategy instances.
10+ *
11+ * Encapsulates the logic for selecting the appropriate lock strategy implementation
12+ * based on available infrastructure (Redis vs in-memory).
13+ */
14+ export class LockStrategyFactory {
15+ /**
16+ * Creates a LockStrategy instance.
17+ *
18+ * @param redisClient - Optional Redis client. If provided, creates Redis-backed lock strategy;
19+ * otherwise creates local in-memory lock strategy.
20+ * @param logger - Logger instance for the lock strategy.
21+ * @returns A LockStrategy implementation.
22+ */
23+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24+ static create ( redisClient : RedisClientType | undefined , logger : Logger ) : LockStrategy {
25+ // TODO: Remove placeholder errors once strategies are implemented
26+ if ( redisClient ) {
27+ throw new Error ( 'Redis lock strategy not yet implemented' ) ;
28+ }
29+
30+ throw new Error ( 'Local lock strategy not yet implemented' ) ;
31+ }
32+ }
Original file line number Diff line number Diff line change @@ -13,3 +13,4 @@ export * from './spendingPlanConfig';
1313export * from './registry' ;
1414export * from './debug' ;
1515export * from './rateLimiter' ;
16+ export * from './lock' ;
Original file line number Diff line number Diff line change 1+ // SPDX-License-Identifier: Apache-2.0
2+
3+ /**
4+ * Interface for lock strategy implementations.
5+ * Strategies handle the actual locking mechanism (local in-memory or distributed via Redis).
6+ *
7+ * @remarks
8+ * Implementations must normalize addresses (e.g., lowercase) internally to ensure consistency.
9+ */
10+ export interface LockStrategy {
11+ /**
12+ * Acquires a lock for the specified address.
13+ * Blocks until the lock is available or timeout is reached.
14+ *
15+ * @param address - The address to acquire the lock for (will be normalized by implementation).
16+ * @returns A promise that resolves to a unique session key upon successful acquisition.
17+ */
18+ acquireLock ( address : string ) : Promise < string > ;
19+
20+ /**
21+ * Releases a lock for the specified address.
22+ * Only succeeds if the provided session key matches the current lock holder.
23+ *
24+ * @param address - The address to release the lock for (will be normalized by implementation).
25+ * @param sessionKey - The session key proving ownership of the lock.
26+ * @returns A promise that resolves when the lock is released or rejected if not owner.
27+ */
28+ releaseLock ( address : string , sessionKey : string ) : Promise < void > ;
29+ }
You can’t perform that action at this time.
0 commit comments