@@ -6,14 +6,63 @@ class Queue
66
77 class << self
88 def all
9- Job . select ( :queue_name ) . distinct . collect do |job |
10- new ( job . queue_name )
9+ queue_names . collect do |queue_name |
10+ new ( queue_name )
1111 end
1212 end
1313
1414 def find_by_name ( name )
1515 new ( name )
1616 end
17+
18+ private
19+
20+ def queue_names
21+ # PostgreSQL doesn't perform well with SELECT DISTINCT
22+ # => Use recursive common table expressions if possible for better performance (https://wiki.postgresql.org/wiki/Loose_indexscan)
23+ if SolidQueue ::Record . connection . adapter_name . downcase == "postgresql" && SolidQueue ::Record . connection . supports_common_table_expressions?
24+ Job . connection . execute ( queue_names_recursive_cte_sql ) . to_a . map { |row | row [ "queue_name" ] }
25+ else
26+ Job . select ( :queue_name ) . distinct . map ( &:queue_name )
27+ end
28+ end
29+
30+ def queue_names_recursive_cte_sql
31+ # This relies on the fact that queue_name in solid_queue_jobs is NOT NULL
32+ # The sql looks something like below:
33+ # WITH RECURSIVE t AS (
34+ # (SELECT queue_name FROM solid_queue_jobs ORDER BY queue_name LIMIT 1) -- parentheses required
35+ # UNION ALL
36+ # SELECT (SELECT queue_name FROM solid_queue_jobs WHERE queue_name > t.queue_name ORDER BY queue_name LIMIT 1)
37+ # FROM t
38+ # WHERE t.queue_name IS NOT NULL
39+ # )
40+ # SELECT queue_name FROM t WHERE queue_name IS NOT NULL;
41+
42+ cte_table = Arel ::Table . new ( :t )
43+ jobs_table = Job . arel_table
44+
45+ cte_base_case = jobs_table . project ( jobs_table [ :queue_name ] ) . order ( jobs_table [ :queue_name ] ) . take ( 1 )
46+
47+ subquery = jobs_table
48+ . project ( jobs_table [ :queue_name ] )
49+ . where ( jobs_table [ :queue_name ] . gt ( cte_table [ :queue_name ] ) )
50+ . order ( jobs_table [ :queue_name ] )
51+ . take ( 1 )
52+ cte_recursive_case = cte_table . project ( subquery )
53+ . where ( cte_table [ :queue_name ] . not_eq ( nil ) )
54+
55+ cte_definition = Arel ::Nodes ::Cte . new (
56+ Arel . sql ( "t" ) ,
57+ Arel ::Nodes ::UnionAll . new ( cte_base_case , cte_recursive_case ) ,
58+ )
59+
60+ cte_table
61+ . project ( cte_table [ :queue_name ] )
62+ . where ( cte_table [ :queue_name ] . not_eq ( nil ) )
63+ . with ( :recursive , cte_definition )
64+ . to_sql
65+ end
1766 end
1867
1968 def initialize ( name )
0 commit comments