@@ -659,6 +659,11 @@ describe("VisibilityManager", () => {
659659 const queueCount = await redis . zcard ( queueKey ) ;
660660 expect ( queueCount ) . toBe ( 1 ) ;
661661
662+ // Verify message is back in queue with its original timestamp (not the deadline)
663+ const queueMessages = await redis . zrange ( queueKey , 0 , - 1 , "WITHSCORES" ) ;
664+ expect ( queueMessages [ 0 ] ) . toBe ( messageId ) ;
665+ expect ( parseInt ( queueMessages [ 1 ] ! ) ) . toBe ( storedMessage . timestamp ) ;
666+
662667 // Verify message is no longer in-flight
663668 const inflightCount = await manager . getTotalInflightCount ( ) ;
664669 expect ( inflightCount ) . toBe ( 0 ) ;
@@ -775,6 +780,71 @@ describe("VisibilityManager", () => {
775780 await redis . quit ( ) ;
776781 }
777782 ) ;
783+
784+ redisTest (
785+ "should use fallback tenantId extraction when message data is missing or corrupted" ,
786+ { timeout : 10000 } ,
787+ async ( { redisOptions } ) => {
788+ keys = new DefaultFairQueueKeyProducer ( { prefix : "test" } ) ;
789+
790+ const manager = new VisibilityManager ( {
791+ redis : redisOptions ,
792+ keys,
793+ shardCount : 1 ,
794+ defaultTimeoutMs : 100 ,
795+ } ) ;
796+
797+ const redis = createRedisClient ( redisOptions ) ;
798+ const queueId = "tenant:t1:queue:fallback-test" ;
799+ const queueKey = keys . queueKey ( queueId ) ;
800+ const queueItemsKey = keys . queueItemsKey ( queueId ) ;
801+ const masterQueueKey = keys . masterQueueKey ( 0 ) ;
802+ const inflightDataKey = keys . inflightDataKey ( 0 ) ;
803+
804+ // Add and claim a message
805+ const messageId = "fallback-msg" ;
806+ const storedMessage = {
807+ id : messageId ,
808+ queueId,
809+ tenantId : "t1" ,
810+ payload : { id : 1 } ,
811+ timestamp : Date . now ( ) - 1000 ,
812+ attempt : 1 ,
813+ metadata : { orgId : "org-123" } ,
814+ } ;
815+
816+ await redis . zadd ( queueKey , storedMessage . timestamp , messageId ) ;
817+ await redis . hset ( queueItemsKey , messageId , JSON . stringify ( storedMessage ) ) ;
818+
819+ // Claim the message
820+ const claimResult = await manager . claim ( queueId , queueKey , queueItemsKey , "consumer-1" , 100 ) ;
821+ expect ( claimResult . claimed ) . toBe ( true ) ;
822+
823+ // Corrupt the in-flight data by setting invalid JSON
824+ await redis . hset ( inflightDataKey , messageId , "not-valid-json{{{" ) ;
825+
826+ // Wait for timeout
827+ await new Promise ( ( resolve ) => setTimeout ( resolve , 150 ) ) ;
828+
829+ // Reclaim should still work using fallback extraction
830+ const reclaimedMessages = await manager . reclaimTimedOut ( 0 , ( qId ) => ( {
831+ queueKey : keys . queueKey ( qId ) ,
832+ queueItemsKey : keys . queueItemsKey ( qId ) ,
833+ masterQueueKey,
834+ } ) ) ;
835+
836+ expect ( reclaimedMessages ) . toHaveLength ( 1 ) ;
837+ expect ( reclaimedMessages [ 0 ] ) . toEqual ( {
838+ messageId,
839+ queueId,
840+ tenantId : "t1" , // Extracted from queueId via fallback
841+ metadata : { } , // Empty metadata since we couldn't parse the stored message
842+ } ) ;
843+
844+ await manager . close ( ) ;
845+ await redis . quit ( ) ;
846+ }
847+ ) ;
778848 } ) ;
779849} ) ;
780850
0 commit comments