@@ -6,14 +6,63 @@ class Queue
6
6
7
7
class << self
8
8
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 )
11
11
end
12
12
end
13
13
14
14
def find_by_name ( name )
15
15
new ( name )
16
16
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
17
66
end
18
67
19
68
def initialize ( name )
0 commit comments