@@ -9,10 +9,37 @@ import { Integration } from "./interfaces/integration";
99
1010const chalk = require ( "chalk" ) ;
1111
12- const queueNameRegExp = new RegExp ( "(.*):(.*):id" ) ;
1312const maxCount = 150000 ;
1413const maxTime = 40000 ;
1514
15+ const parseQueueKey = ( key : string ) => {
16+ const suffixSeparator = key . lastIndexOf ( ":" ) ;
17+ if ( suffixSeparator === - 1 ) {
18+ return ;
19+ }
20+
21+ const keySuffix = key . slice ( suffixSeparator + 1 ) ;
22+ if ( keySuffix !== "id" && keySuffix !== "meta" ) {
23+ return ;
24+ }
25+
26+ const prefixAndQueueName = key . slice ( 0 , suffixSeparator ) ;
27+ const queueNameSeparator = prefixAndQueueName . lastIndexOf ( ":" ) ;
28+
29+ if ( queueNameSeparator === - 1 ) {
30+ return ;
31+ }
32+
33+ const prefix = prefixAndQueueName . slice ( 0 , queueNameSeparator ) ;
34+ const name = prefixAndQueueName . slice ( queueNameSeparator + 1 ) ;
35+
36+ if ( ! prefix || ! name ) {
37+ return ;
38+ }
39+
40+ return { prefix, name } ;
41+ } ;
42+
1643export type RedisConnection = Redis | Cluster ;
1744
1845// We keep a redis client that we can reuse for all the queues.
@@ -28,9 +55,9 @@ export interface FoundQueue {
2855
2956const scanForQueues = async ( node : Redis | Cluster , startTime : number ) => {
3057 let cursor = "0" ;
31- const keys = [ ] ;
58+ const keys = new Set < string > ( ) ;
3259 do {
33- const [ nextCursor , scannedKeys ] = await node . scan (
60+ const [ nextCursor , scannedIdKeys ] = await node . scan (
3461 cursor ,
3562 "MATCH" ,
3663 "*:*:id" ,
@@ -39,62 +66,78 @@ const scanForQueues = async (node: Redis | Cluster, startTime: number) => {
3966 "TYPE" ,
4067 "string"
4168 ) ;
69+ const [ , scannedMetaKeys ] = await node . scan (
70+ cursor ,
71+ "MATCH" ,
72+ "*:*:meta" ,
73+ "COUNT" ,
74+ maxCount ,
75+ "TYPE" ,
76+ "hash"
77+ ) ;
4278 cursor = nextCursor ;
4379
44- keys . push ( ...scannedKeys ) ;
80+ scannedIdKeys . forEach ( ( key ) => keys . add ( key ) ) ;
81+ scannedMetaKeys . forEach ( ( key ) => keys . add ( key . replace ( / : m e t a $ / , ":id" ) ) ) ;
4582 } while ( Date . now ( ) - startTime < maxTime && cursor !== "0" ) ;
4683
47- return keys ;
84+ return [ ... keys ] ;
4885} ;
4986
5087const getQueueKeys = async ( client : Redis | Cluster , queueNames ?: string [ ] ) => {
5188 let nodes = "nodes" in client ? client . nodes ( "master" ) : [ client ] ;
52- let keys = [ ] ;
89+ let keys : string [ ] = [ ] ;
5390 const startTime = Date . now ( ) ;
5491 const foundQueues = new Set < string > ( ) ;
92+ const queueKeys = queueNames ?. map ( ( queueName ) => {
93+ // Separate queue name from prefix
94+ let [ prefix , name ] = queueName . split ( ":" ) ;
95+ if ( ! name ) {
96+ name = prefix ;
97+ prefix = "bull" ;
98+ }
99+
100+ // If the queue name includes a prefix use that, otherwise use the default prefix "bull"
101+ return `${ prefix } :${ name } :id` ;
102+ } ) ;
55103
56104 for await ( const node of nodes ) {
57105 // If we have proposed queue names, lets check if they exist (including prefix)
58106 // Basically checking if there is a id key for the queue (prefix:name:id)
59- if ( queueNames ) {
60- const queueKeys = queueNames . map ( ( queueName ) => {
61- // Separate queue name from prefix
62- let [ prefix , name ] = queueName . split ( ":" ) ;
63- if ( ! name ) {
64- name = prefix ;
65- prefix = "bull" ;
107+ if ( queueKeys ) {
108+ for ( const key of queueKeys ) {
109+ if ( foundQueues . has ( key ) ) {
110+ continue ;
66111 }
67112
68- // If the queue name includes a prefix use that, otherwise use the default prefix "bull"
69- return `${ prefix } :${ name } :id` ;
70- } ) ;
71-
72- for ( const key of queueKeys ) {
73- const exists = await node . exists ( key ) ;
113+ const metaKey = key . replace ( / : i d $ / , ":meta" ) ;
114+ const exists = await node . exists ( key , metaKey ) ;
74115 if ( exists ) {
75116 foundQueues . add ( key ) ;
76117 }
77118 }
78- keys . push ( ...foundQueues ) ;
79-
80- // Warn for missing queues
81- for ( const key of queueKeys ) {
82- if ( ! foundQueues . has ( key ) ) {
83- // Extract queue name from key
84- const match = queueNameRegExp . exec ( key ) ;
85- const queueLabel = match ? `${ match [ 1 ] } :${ match [ 2 ] } ` : key ;
86- console . log (
87- chalk . yellow ( "Redis:" ) +
88- chalk . red (
89- ` Queue "${ queueLabel } " not found in Redis. Skipping...`
90- )
91- ) ;
92- }
93- }
94119 } else {
95120 keys . push ( ...( await scanForQueues ( node , startTime ) ) ) ;
96121 }
97122 }
123+
124+ if ( queueKeys ) {
125+ keys . push ( ...foundQueues ) ;
126+
127+ // Warn for missing queues
128+ for ( const key of queueKeys ) {
129+ if ( ! foundQueues . has ( key ) ) {
130+ // Extract queue name from key
131+ const queue = parseQueueKey ( key ) ;
132+ const queueLabel = queue ? `${ queue . prefix } :${ queue . name } ` : key ;
133+ console . log (
134+ chalk . yellow ( "Redis:" ) +
135+ chalk . red ( ` Queue "${ queueLabel } " not found in Redis. Skipping...` )
136+ ) ;
137+ }
138+ }
139+ }
140+
98141 return keys ;
99142} ;
100143
@@ -112,11 +155,11 @@ export async function getConnectionQueues(
112155 const queues = await Promise . all (
113156 keys
114157 . map ( function ( key ) {
115- var match = queueNameRegExp . exec ( key ) ;
116- if ( match ) {
158+ const queue = parseQueueKey ( key ) ;
159+ if ( queue ) {
117160 return {
118- prefix : match [ 1 ] ,
119- name : match [ 2 ] ,
161+ prefix : queue . prefix ,
162+ name : queue . name ,
120163 type : "bull" , // default to bull
121164 } ;
122165 }
0 commit comments