@@ -61,54 +61,6 @@ export function getRedisClient(): Redis | null {
6161 }
6262}
6363
64- /**
65- * Check if Redis is ready for commands.
66- * Use for health checks only - commands should be sent regardless (ioredis queues them).
67- */
68- export function isRedisConnected ( ) : boolean {
69- return globalRedisClient ?. status === 'ready'
70- }
71-
72- /**
73- * Get Redis connection status for diagnostics.
74- */
75- export function getRedisStatus ( ) : string {
76- return globalRedisClient ?. status ?? 'not initialized'
77- }
78-
79- const MESSAGE_ID_PREFIX = 'processed:'
80- const MESSAGE_ID_EXPIRY = 60 * 60 * 24 * 7
81-
82- /**
83- * Check if a message has been processed (for idempotency).
84- * Requires Redis - throws if Redis is not available.
85- */
86- export async function hasProcessedMessage ( key : string ) : Promise < boolean > {
87- const redis = getRedisClient ( )
88- if ( ! redis ) {
89- throw new Error ( 'Redis not available for message deduplication' )
90- }
91-
92- const result = await redis . exists ( `${ MESSAGE_ID_PREFIX } ${ key } ` )
93- return result === 1
94- }
95-
96- /**
97- * Mark a message as processed (for idempotency).
98- * Requires Redis - throws if Redis is not available.
99- */
100- export async function markMessageAsProcessed (
101- key : string ,
102- expirySeconds : number = MESSAGE_ID_EXPIRY
103- ) : Promise < void > {
104- const redis = getRedisClient ( )
105- if ( ! redis ) {
106- throw new Error ( 'Redis not available for message deduplication' )
107- }
108-
109- await redis . set ( `${ MESSAGE_ID_PREFIX } ${ key } ` , '1' , 'EX' , expirySeconds )
110- }
111-
11264/**
11365 * Lua script for safe lock release.
11466 * Only deletes the key if the value matches (ownership verification).
12577/**
12678 * Acquire a distributed lock using Redis SET NX.
12779 * Returns true if lock acquired, false if already held.
128- * Requires Redis - throws if Redis is not available.
80+ *
81+ * When Redis is not available, returns true (lock "acquired") to allow
82+ * single-replica deployments to function without Redis. In multi-replica
83+ * deployments without Redis, the idempotency layer prevents duplicate processing.
12984 */
13085export async function acquireLock (
13186 lockKey : string ,
@@ -134,36 +89,24 @@ export async function acquireLock(
13489) : Promise < boolean > {
13590 const redis = getRedisClient ( )
13691 if ( ! redis ) {
137- throw new Error ( ' Redis not available for distributed locking' )
92+ return true // No-op when Redis unavailable; idempotency layer handles duplicates
13893 }
13994
14095 const result = await redis . set ( lockKey , value , 'EX' , expirySeconds , 'NX' )
14196 return result === 'OK'
14297}
14398
144- /**
145- * Get the value of a lock key.
146- * Requires Redis - throws if Redis is not available.
147- */
148- export async function getLockValue ( key : string ) : Promise < string | null > {
149- const redis = getRedisClient ( )
150- if ( ! redis ) {
151- throw new Error ( 'Redis not available' )
152- }
153-
154- return redis . get ( key )
155- }
156-
15799/**
158100 * Release a distributed lock safely.
159101 * Only releases if the caller owns the lock (value matches).
160102 * Returns true if lock was released, false if not owned or already expired.
161- * Requires Redis - throws if Redis is not available.
103+ *
104+ * When Redis is not available, returns true (no-op) since no lock was held.
162105 */
163106export async function releaseLock ( lockKey : string , value : string ) : Promise < boolean > {
164107 const redis = getRedisClient ( )
165108 if ( ! redis ) {
166- throw new Error ( ' Redis not available for distributed locking' )
109+ return true // No-op when Redis unavailable; no lock was actually held
167110 }
168111
169112 const result = await redis . eval ( RELEASE_LOCK_SCRIPT , 1 , lockKey , value )
0 commit comments