queue_classic 3.2.0.RC1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/codeql-analysis.yml +72 -0
- data/.github/workflows/main.yaml +71 -0
- data/.gitignore +2 -0
- data/{changelog → CHANGELOG.md} +87 -34
- data/CODE_OF_CONDUCT.md +46 -0
- data/Gemfile +9 -5
- data/README.md +103 -126
- data/Rakefile +2 -0
- data/lib/generators/queue_classic/install_generator.rb +6 -0
- data/lib/generators/queue_classic/templates/add_queue_classic.rb +3 -1
- data/lib/generators/queue_classic/templates/update_queue_classic_3_0_0.rb +3 -1
- data/lib/generators/queue_classic/templates/update_queue_classic_3_0_2.rb +3 -1
- data/lib/generators/queue_classic/templates/update_queue_classic_3_1_0.rb +3 -1
- data/lib/generators/queue_classic/templates/update_queue_classic_4_0_0.rb +11 -0
- data/lib/queue_classic/config.rb +2 -1
- data/lib/queue_classic/conn_adapter.rb +29 -15
- data/lib/queue_classic/queue.rb +66 -12
- data/lib/queue_classic/railtie.rb +2 -0
- data/lib/queue_classic/setup.rb +24 -7
- data/lib/queue_classic/tasks.rb +4 -5
- data/lib/queue_classic/version.rb +3 -1
- data/lib/queue_classic/worker.rb +15 -6
- data/lib/queue_classic.rb +4 -11
- data/queue_classic.gemspec +3 -2
- data/sql/create_table.sql +7 -16
- data/sql/ddl.sql +6 -82
- data/sql/downgrade_from_4_0_0.sql +88 -0
- data/sql/update_to_3_0_0.sql +5 -5
- data/sql/update_to_3_1_0.sql +6 -6
- data/sql/update_to_4_0_0.sql +6 -0
- data/test/benchmark_test.rb +2 -0
- data/test/config_test.rb +2 -0
- data/test/helper.rb +34 -0
- data/test/lib/queue_classic_rails_connection_test.rb +9 -6
- data/test/lib/queue_classic_test.rb +2 -0
- data/test/lib/queue_classic_test_with_activerecord_typecast.rb +21 -0
- data/test/queue_test.rb +62 -2
- data/test/rails-tests/.gitignore +2 -0
- data/test/rails-tests/rails523.sh +23 -0
- data/test/worker_test.rb +138 -17
- metadata +43 -13
- data/.travis.yml +0 -15
data/README.md
CHANGED
@@ -1,41 +1,54 @@
|
|
1
1
|
# queue_classic
|
2
|
+
A simple, efficient worker queue for Ruby & PostgreSQL.
|
2
3
|
|
3
|
-
|
4
|
-
<b>Simple, efficient worker queue for Ruby & PostgreSQL</b>
|
5
|
-
<br />
|
6
|
-
<a href="https://travis-ci.org/QueueClassic/queue_classic"><img src="http://img.shields.io/travis/QueueClassic/queue_classic/master.svg?style=flat" /></a>
|
4
|
+
Why this over something like Resque. Two reasons:
|
7
5
|
|
8
|
-
|
6
|
+
1. Your jobs can be equeued in the same transaction as other modifications to the database, and will only be processed when everything is commited. This is a hard pattern to develop around for queues done outside your database
|
7
|
+
2. Less things to run, if you don't already have Redis or a dedicated queue in your stack.
|
9
8
|
|
10
|
-
|
11
|
-
</p>
|
9
|
+
![master](https://github.com/QueueClassic/queue_classic/actions/workflows/main.yaml/badge.svg?branch=master)
|
12
10
|
|
11
|
+
[![Gem Version](http://img.shields.io/gem/v/queue_classic.svg?style=flat)](http://badge.fury.io/rb/queue_classic)
|
13
12
|
|
14
|
-
**IMPORTANT NOTE
|
13
|
+
**IMPORTANT NOTE: This README is representing the current work for queue_classic, which is generally the pending next version.**
|
15
14
|
|
16
|
-
|
15
|
+
You can always find the latest and previous releases here:
|
17
16
|
|
18
|
-
|
19
|
-
- latest stable can be found: [v3.0.X](https://github.com/QueueClassic/queue_classic/tree/3-0-stable)
|
20
|
-
- older stable: [v2.2.3](https://github.com/QueueClassic/queue_classic/tree/v2.2.3)
|
17
|
+
https://github.com/QueueClassic/queue_classic/releases
|
21
18
|
|
19
|
+
## Other related projects
|
20
|
+
If you're interested in this project, you might also want to checkout:
|
22
21
|
|
23
|
-
|
22
|
+
* [Que](https://github.com/que-rb/que)
|
23
|
+
* [GoodJob](https://github.com/bensheldon/good_job)
|
24
|
+
* [Delayed Job](https://github.com/collectiveidea/delayed_job)
|
25
|
+
|
26
|
+
For a list of other queues (which may or may not be Postgres backed), checkout - https://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html
|
24
27
|
|
28
|
+
## What is queue_classic?
|
25
29
|
queue_classic provides a simple interface to a PostgreSQL-backed message queue. queue_classic specializes in concurrent locking and minimizing database load while providing a simple, intuitive developer experience. queue_classic assumes that you are already using PostgreSQL in your production environment and that adding another dependency (e.g. redis, beanstalkd, 0mq) is undesirable.
|
26
30
|
|
27
|
-
|
31
|
+
A major benefit is the ability to enqueue inside transactions, ensuring things are done only when your changes are commited.
|
28
32
|
|
29
|
-
|
33
|
+
## Other related projects
|
34
|
+
* [Queue Classic Plus](https://github.com/rainforestapp/queue_classic_plus) - adds support for retrying with specific exceptions, transaction processing of jobs, metric collection, etc
|
35
|
+
* [Queue Classic Admin](https://github.com/QueueClassic/queue_classic_admin) - Admin interface for queue_classic
|
36
|
+
* [Queue Classic Matchers](https://github.com/rainforestapp/queue_classic_matchers) - RSpec matchers for queue_classic
|
37
|
+
|
38
|
+
## Features
|
39
|
+
* Leverage of PostgreSQL's listen/notify, skip locked, and row locking.
|
30
40
|
* Support for multiple queues with heterogeneous workers.
|
31
41
|
* JSON data format.
|
32
|
-
* Forking workers.
|
33
42
|
* Workers can work multiple queues.
|
34
|
-
* Reduced row contention using a [relaxed FIFO](http://www.cs.tau.ac.il/~shanir/nir-pubs-web/Papers/Lock_Free.pdf) technique.
|
35
43
|
|
36
|
-
|
44
|
+
### Requirements
|
45
|
+
For this version, the requirements are as follows:
|
46
|
+
* Ruby 2.6, 2.7, 3.0, 3.1 - i.e. currently supported Ruby versions
|
47
|
+
* Postgres ~> 9.6
|
48
|
+
* Rubygem: pg ~> 1.1
|
37
49
|
|
38
|
-
|
50
|
+
## Table of contents
|
51
|
+
* [Documentation](https://www.rubydoc.info/gems/queue_classic/)
|
39
52
|
* [Usage](#usage)
|
40
53
|
* [Setup](#setup)
|
41
54
|
* [Upgrade from earlier versions to V3.1](#upgrade-from-earlier-versions)
|
@@ -47,15 +60,14 @@ queue_classic provides a simple interface to a PostgreSQL-backed message queue.
|
|
47
60
|
* [License](#license)
|
48
61
|
|
49
62
|
## Usage
|
50
|
-
|
51
|
-
There are 2 ways to use queue_classic.
|
63
|
+
There are 2 ways to use queue_classic:
|
52
64
|
|
53
65
|
* Producing Jobs
|
54
66
|
* Working Jobs
|
55
67
|
|
56
68
|
### Producing Jobs
|
57
|
-
|
58
|
-
The first argument is a string which represents a ruby object and a method name. The second argument(s) will be passed along as arguments to the method
|
69
|
+
#### Simple Enqueue
|
70
|
+
The first argument is a string which represents a ruby object and a method name. The second argument(s) will be passed along as arguments to the method defined by the first argument. The set of arguments will be encoded as JSON and stored in the database.
|
59
71
|
|
60
72
|
```ruby
|
61
73
|
# This method has no arguments.
|
@@ -78,47 +90,50 @@ p_queue = QC::Queue.new("priority_queue")
|
|
78
90
|
p_queue.enqueue("Kernel.puts", ["hello", "world"])
|
79
91
|
```
|
80
92
|
|
81
|
-
|
93
|
+
#### Scheduling for later
|
94
|
+
There is also the ability to schedule a job to run at a specified time in the future. The job will become processable after the specified time, and will be processed as-soon-as-possible.
|
82
95
|
|
83
96
|
```ruby
|
84
|
-
#
|
97
|
+
# Specify the job execution time exactly
|
85
98
|
QC.enqueue_at(Time.new(2024,01,02,10,00), "Kernel.puts", "hello future")
|
86
99
|
|
87
|
-
#
|
100
|
+
# Specify the job execution time as an offset in seconds
|
88
101
|
QC.enqueue_in(60, "Kernel.puts", "hello from 1 minute later")
|
89
102
|
```
|
90
103
|
|
91
104
|
### Working Jobs
|
92
|
-
|
93
|
-
There are two ways to work jobs. The first approach is to use the Rake task. The second approach is to use a custom executable.
|
105
|
+
There are two ways to work/process jobs. The first approach is to use the Rake task. The second approach is to use a custom executable.
|
94
106
|
|
95
107
|
#### Rake Task
|
96
|
-
|
97
|
-
Require queue_classic in your Rakefile.
|
108
|
+
Require queue_classic in your Rakefile:
|
98
109
|
|
99
110
|
```ruby
|
100
111
|
require 'queue_classic'
|
101
112
|
require 'queue_classic/tasks'
|
102
113
|
```
|
103
114
|
|
104
|
-
|
115
|
+
##### Work all queues
|
116
|
+
Start the worker via the Rakefile:
|
117
|
+
|
105
118
|
```bash
|
106
|
-
|
119
|
+
bundle exec rake qc:work
|
107
120
|
```
|
108
121
|
|
109
|
-
|
122
|
+
##### Work a single specific queue
|
123
|
+
Setup a worker to work only a specific, non-default queue:
|
124
|
+
|
110
125
|
```bash
|
111
|
-
|
126
|
+
QUEUE="priority_queue" bundle exec rake qc:work
|
112
127
|
```
|
113
128
|
|
114
|
-
|
129
|
+
##### Work multiple queues
|
130
|
+
In this scenario, on each iteration of the worker's loop, it will look for jobs in the first queue prior to looking at the second queue. This means that the first queue must be empty before the worker will look at the second queue.
|
131
|
+
|
115
132
|
```bash
|
116
|
-
|
133
|
+
QUEUES="priority_queue,secondary_queue" bundle exec rake qc:work
|
117
134
|
```
|
118
|
-
In this scenario, on each iteration of the worker's loop, it will look for jobs in the first queue prior to looking at the second queue. This means that the first queue must be empty before the worker will look at the second queue.
|
119
135
|
|
120
136
|
#### Custom Worker
|
121
|
-
|
122
137
|
This example is probably not production ready; however, it serves as an example of how to leverage the code in the Worker class to fit your non-default requirements.
|
123
138
|
|
124
139
|
```ruby
|
@@ -128,7 +143,6 @@ require 'queue_classic'
|
|
128
143
|
FailedQueue = QC::Queue.new("failed_jobs")
|
129
144
|
|
130
145
|
class MyWorker < QC::Worker
|
131
|
-
|
132
146
|
# A job is a Hash containing these attributes:
|
133
147
|
# :id Integer, the job id
|
134
148
|
# :method String, containing the object and method
|
@@ -141,7 +155,7 @@ class MyWorker < QC::Worker
|
|
141
155
|
# Do something with the job
|
142
156
|
...
|
143
157
|
end
|
144
|
-
|
158
|
+
|
145
159
|
# This method will be called when an exception
|
146
160
|
# is raised during the execution of the job.
|
147
161
|
# First argument is the job that failed.
|
@@ -149,7 +163,6 @@ class MyWorker < QC::Worker
|
|
149
163
|
def handle_failure(job, e)
|
150
164
|
FailedQueue.enqueue(job[:method], *job[:args])
|
151
165
|
end
|
152
|
-
|
153
166
|
end
|
154
167
|
|
155
168
|
worker = MyWorker.new
|
@@ -158,164 +171,128 @@ trap('INT') { exit }
|
|
158
171
|
trap('TERM') { worker.stop }
|
159
172
|
|
160
173
|
loop do
|
161
|
-
job = worker.lock_job
|
162
|
-
Timeout::timeout(5) { worker.process(job) }
|
174
|
+
queue, job = worker.lock_job
|
175
|
+
Timeout::timeout(5) { worker.process(queue, job) }
|
163
176
|
end
|
164
177
|
```
|
165
178
|
|
166
|
-
The `qc:work` rake task uses `QC::Worker` by default. However, it's easy to
|
167
|
-
inject your own worker class:
|
179
|
+
The `qc:work` rake task uses `QC::Worker` by default. However, it's easy to inject your own worker class:
|
168
180
|
|
169
181
|
```ruby
|
170
182
|
QC.default_worker_class = MyWorker
|
171
183
|
```
|
172
184
|
|
173
185
|
## Setup
|
174
|
-
|
175
|
-
In addition to installing the rubygem, you will need to prepare your database. Database preparation includes creating a table and loading PL/pgSQL functions. You can issue the database preparation commands using `PSQL(1)` or use a database migration script.
|
186
|
+
In addition to installing the rubygem, you will need to prepare your database. Database preparation includes creating a table and loading PL/pgSQL functions. You can issue the database preparation commands using `psql` or use a database migration script.
|
176
187
|
|
177
188
|
### Quick Start
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
$ ruby -r queue_classic -e "QC::Worker.new.work"
|
189
|
+
```bash{:copy}
|
190
|
+
gem install queue_classic
|
191
|
+
createdb queue_classic_test
|
192
|
+
export QC_DATABASE_URL="postgres://username:password@localhost/queue_classic_test"
|
193
|
+
ruby -r queue_classic -e "QC::Setup.create"
|
194
|
+
ruby -r queue_classic -e "QC.enqueue('Kernel.puts', 'hello world')"
|
195
|
+
ruby -r queue_classic -e "QC::Worker.new.work"
|
186
196
|
```
|
187
197
|
|
188
198
|
### Ruby on Rails Setup
|
199
|
+
Declare dependencies in Gemfile:
|
189
200
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
201
|
+
```ruby{:copy}
|
202
|
+
source 'https://rubygems.org' do
|
203
|
+
gem 'queue_classic'
|
204
|
+
end
|
194
205
|
```
|
195
206
|
|
196
|
-
|
207
|
+
Install queue_classic, which adds the needed migrations for the database tables and stored procedures:
|
197
208
|
|
198
|
-
```
|
209
|
+
```bash
|
199
210
|
rails generate queue_classic:install
|
200
211
|
bundle exec rake db:migrate
|
201
212
|
```
|
202
213
|
|
203
|
-
####
|
214
|
+
#### Database connection
|
215
|
+
Starting with with queue_classic 3.1, Rails is automatically detected and its connection is used. If you don't want to use the automatic database connection, set this environment variable to false: `export QC_RAILS_DATABASE=false`.
|
204
216
|
|
205
|
-
|
217
|
+
> **Note:** If you do not share the connection, you cannot enqueue in the same transaction as whatever you're doing in Rails.
|
206
218
|
|
207
|
-
|
219
|
+
**Note on using ActiveRecord migrations:** If you use the migration, and you wish to use commands that reset the database from the stored schema (e.g. `rake db:reset`), your application must be configured with `config.active_record.schema_format = :sql` in `config/application.rb`. If you don't do this, the PL/pgSQL function that queue_classic creates will be lost when you reset the database.
|
208
220
|
|
209
|
-
|
221
|
+
#### Active Job
|
222
|
+
If you use Rails 4.2+ and want to use Active Job, all you need to do is to set `config.active_job.queue_adapter = :queue_classic` in your `application.rb`. Everything else will be taken care for you. You can now use the Active Job functionality from now.
|
210
223
|
|
211
|
-
|
224
|
+
### Plain Ruby Setup
|
225
|
+
If you're not using Rails, you can use the Rake task to prepare your database:
|
212
226
|
|
213
|
-
```bash
|
227
|
+
```bash{:copy}
|
214
228
|
# Creating the table and functions
|
215
|
-
|
229
|
+
bundle exec rake qc:create
|
216
230
|
|
217
231
|
# Dropping the table and functions
|
218
|
-
|
232
|
+
bundle exec rake qc:drop
|
219
233
|
```
|
220
234
|
|
221
|
-
|
235
|
+
#### Database connection
|
236
|
+
By default, queue_classic will use the `QC_DATABASE_URL` falling back on `DATABASE_URL`. The URL must be in the following format: `postgres://username:password@localhost/database_name`. If you use Heroku's PostgreSQL service, this will already be set. If you don't want to set this variable, you can set the connection in an initializer. **QueueClassic will maintain its own connection to the database.** This may double the number of connections to your database.
|
222
237
|
|
223
|
-
|
224
|
-
|
225
|
-
Starting with with queue_classic 3.1, Rails is automatically detected and its connection is used.
|
226
|
-
|
227
|
-
If you don't want to use the automatic database connection, set this environment variable to false: `export QC_RAILS_DATABASE=false`
|
228
|
-
|
229
|
-
**Note on using ActiveRecord migrations:** If you use the migration, and you wish to use commands that reset the database from the stored schema (e.g. `rake db:reset`), your application must be configured with `config.active_record.schema_format = :sql` in `config/application.rb`. If you don't do this, the PL/pgSQL function that queue_classic creates will be lost when you reset the database.
|
230
|
-
|
231
|
-
|
232
|
-
#### Other Ruby apps
|
233
|
-
|
234
|
-
By default, queue_classic will use the QC_DATABASE_URL falling back on DATABASE_URL. The URL must be in the following format: `postgres://username:password@localhost/database_name`. If you use Heroku's PostgreSQL service, this will already be set. If you don't want to set this variable, you can set the connection in an initializer. **QueueClassic will maintain its own connection to the database.** This may double the number of connections to your database.
|
235
|
-
|
236
|
-
## Upgrade from earlier versions
|
238
|
+
## Upgrading from earlier versions
|
237
239
|
If you are upgrading from a previous version of queue_classic, you might need some new database columns and/or functions. Luckily enough for you, it is easy to do so.
|
238
240
|
|
239
241
|
### Ruby on Rails
|
242
|
+
These two commands will add the newer migrations:
|
240
243
|
|
241
|
-
|
242
|
-
|
243
|
-
```
|
244
|
+
```bash{:copy}
|
244
245
|
rails generate queue_classic:install
|
245
246
|
bundle exec rake db:migrate
|
246
247
|
```
|
248
|
+
|
247
249
|
### Rake Task
|
250
|
+
This rake task will update you to the latest version:
|
248
251
|
|
249
|
-
|
250
|
-
```bash
|
252
|
+
```bash{:copy}
|
251
253
|
# Updating the table and functions
|
252
|
-
|
254
|
+
bundle exec rake qc:update
|
253
255
|
```
|
254
256
|
|
255
257
|
## Configuration
|
256
|
-
|
257
258
|
All configuration takes place in the form of environment vars. See [queue_classic.rb](https://github.com/QueueClassic/queue_classic/blob/master/lib/queue_classic.rb#L23-62) for a list of options.
|
258
259
|
|
259
|
-
## JSON
|
260
|
-
|
261
|
-
If you are running PostgreSQL 9.4 or higher, queue_classic will use the [jsonb](http://www.postgresql.org/docs/9.4/static/datatype-json.html) datatype for new tables. Versions 9.2 and 9.3 will use the `json` data type and versions 9.1 and lower will use the `text` data type.
|
262
|
-
If you are updating queue_classic and are running PostgreSQL >= 9.4, run the following to switch to `jsonb`:
|
263
|
-
```
|
264
|
-
alter table queue_classic_jobs alter column args type jsonb using (args::jsonb);
|
265
|
-
```
|
266
|
-
|
267
260
|
## Logging
|
268
|
-
|
269
|
-
By default queue_classic does not talk very much.
|
270
|
-
If you find yourself in a situation where you need to know what's happening inside QC, there are two different kind of logging you can enable: DEBUG and MEASURE.
|
261
|
+
By default queue_classic does not talk very much. If you find yourself in a situation where you need to know what's happening inside QC, there are two different kind of logging you can enable: `DEBUG` and `MEASURE`.
|
271
262
|
|
272
263
|
### Measure
|
273
|
-
This will output the time to process and
|
264
|
+
This will output the time to process and some more statistics. To enable it, set the `QC_MEASURE`:
|
274
265
|
|
275
|
-
```
|
266
|
+
```bash{:copy}
|
276
267
|
export QC_MEASURE="true"
|
277
268
|
```
|
278
269
|
|
279
270
|
### Debug
|
280
271
|
You can enable the debug output by setting the `DEBUG` environment variable:
|
281
272
|
|
282
|
-
```
|
273
|
+
```bash{:copy}
|
283
274
|
export DEBUG="true"
|
284
275
|
```
|
285
276
|
|
286
277
|
## Support
|
287
|
-
|
288
278
|
If you think you have found a bug, feel free to open an issue. Use the following template for the new issue:
|
289
279
|
|
290
|
-
1. List
|
280
|
+
1. List your versions: Ruby, PostgreSQL, queue_classic.
|
291
281
|
2. Define what you would have expected to happen.
|
292
282
|
3. List what actually happened.
|
293
283
|
4. Provide sample codes & commands which will reproduce the problem.
|
294
284
|
|
295
|
-
If you have general questions about how to use queue_classic, send a message to the mailing list:
|
296
|
-
|
297
|
-
https://groups.google.com/d/forum/queue_classic
|
298
|
-
|
299
285
|
## Hacking on queue_classic
|
300
|
-
|
301
|
-
### Dependencies
|
302
|
-
|
303
|
-
* Ruby 1.9.2
|
304
|
-
* Postgres ~> 9.0
|
305
|
-
* Rubygem: pg ~> 0.11.0
|
306
|
-
* For JRuby, see [queue_classic_java](https://github.com/bdon/queue_classic_java)
|
307
|
-
|
308
286
|
### Running Tests
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
287
|
+
```bash{:copy}
|
288
|
+
bundle
|
289
|
+
createdb queue_classic_test
|
290
|
+
export QC_DATABASE_URL="postgres://username:pass@localhost/queue_classic_test"
|
291
|
+
bundle exec rake # run all tests
|
292
|
+
bundle exec ruby test/queue_test.rb # run a single test
|
315
293
|
```
|
316
294
|
|
317
295
|
## License
|
318
|
-
|
319
296
|
Copyright (C) 2010 Ryan Smith
|
320
297
|
|
321
298
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rails/generators'
|
2
4
|
require 'rails/generators/migration'
|
3
5
|
require 'active_record'
|
@@ -31,6 +33,10 @@ module QC
|
|
31
33
|
if self.class.migration_exists?('db/migrate', 'update_queue_classic_3_1_0').nil?
|
32
34
|
migration_template 'update_queue_classic_3_1_0.rb', 'db/migrate/update_queue_classic_3_1_0.rb'
|
33
35
|
end
|
36
|
+
|
37
|
+
if self.class.migration_exists?('db/migrate', 'update_queue_classic_4_0_0').nil?
|
38
|
+
migration_template 'update_queue_classic_4_0_0.rb', 'db/migrate/update_queue_classic_4_0_0.rb'
|
39
|
+
end
|
34
40
|
end
|
35
41
|
end
|
36
42
|
end
|
data/lib/queue_classic/config.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module QC
|
2
4
|
module Config
|
3
5
|
# You can use the APP_NAME to query for
|
@@ -58,7 +60,6 @@ module QC
|
|
58
60
|
|
59
61
|
# The worker class instantiated by QC's rake tasks.
|
60
62
|
def default_worker_class
|
61
|
-
|
62
63
|
@worker_class ||= (ENV["QC_DEFAULT_WORKER_CLASS"] && Kernel.const_get(ENV["QC_DEFAULT_WORKER_CLASS"]) ||
|
63
64
|
QC::Worker)
|
64
65
|
|
@@ -1,27 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'pg'
|
3
5
|
|
4
6
|
module QC
|
5
7
|
class ConnAdapter
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
@
|
9
|
+
def initialize(args={})
|
10
|
+
@active_record_connection_share = args[:active_record_connection_share]
|
11
|
+
@_connection = args[:connection]
|
10
12
|
@mutex = Mutex.new
|
11
13
|
end
|
12
14
|
|
15
|
+
def connection
|
16
|
+
if @active_record_connection_share && Object.const_defined?('ActiveRecord')
|
17
|
+
ActiveRecord::Base.connection.raw_connection
|
18
|
+
else
|
19
|
+
@_connection ||= establish_new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
13
23
|
def execute(stmt, *params)
|
14
24
|
@mutex.synchronize do
|
15
25
|
QC.log(:at => "exec_sql", :sql => stmt.inspect)
|
16
26
|
begin
|
17
27
|
params = nil if params.empty?
|
18
|
-
r =
|
28
|
+
r = connection.exec(stmt, params)
|
19
29
|
result = []
|
20
30
|
r.each {|t| result << t}
|
21
31
|
result.length > 1 ? result : result.pop
|
22
|
-
rescue
|
32
|
+
rescue PG::Error => e
|
23
33
|
QC.log(:error => e.inspect)
|
24
|
-
|
34
|
+
connection.reset
|
25
35
|
raise
|
26
36
|
end
|
27
37
|
end
|
@@ -30,10 +40,10 @@ module QC
|
|
30
40
|
def wait(time, *channels)
|
31
41
|
@mutex.synchronize do
|
32
42
|
listen_cmds = channels.map {|c| 'LISTEN "' + c.to_s + '"'}
|
33
|
-
|
43
|
+
connection.exec(listen_cmds.join(';'))
|
34
44
|
wait_for_notify(time)
|
35
45
|
unlisten_cmds = channels.map {|c| 'UNLISTEN "' + c.to_s + '"'}
|
36
|
-
|
46
|
+
connection.exec(unlisten_cmds.join(';'))
|
37
47
|
drain_notify
|
38
48
|
end
|
39
49
|
end
|
@@ -41,7 +51,7 @@ module QC
|
|
41
51
|
def disconnect
|
42
52
|
@mutex.synchronize do
|
43
53
|
begin
|
44
|
-
|
54
|
+
connection.close
|
45
55
|
rescue => e
|
46
56
|
QC.log(:at => 'disconnect', :error => e.message)
|
47
57
|
end
|
@@ -59,12 +69,12 @@ module QC
|
|
59
69
|
|
60
70
|
def wait_for_notify(t)
|
61
71
|
Array.new.tap do |msgs|
|
62
|
-
|
72
|
+
connection.wait_for_notify(t) {|event, pid, msg| msgs << msg}
|
63
73
|
end
|
64
74
|
end
|
65
75
|
|
66
76
|
def drain_notify
|
67
|
-
until
|
77
|
+
until connection.notifies.nil?
|
68
78
|
QC.log(:at => "drain_notifications")
|
69
79
|
end
|
70
80
|
end
|
@@ -77,10 +87,15 @@ module QC
|
|
77
87
|
|
78
88
|
def establish_new
|
79
89
|
QC.log(:at => "establish_conn")
|
80
|
-
conn =
|
81
|
-
if conn.status !=
|
90
|
+
conn = PG.connect(*normalize_db_url(db_url))
|
91
|
+
if conn.status != PG::CONNECTION_OK
|
82
92
|
QC.log(:error => conn.error)
|
83
93
|
end
|
94
|
+
|
95
|
+
if conn.server_version < 90600
|
96
|
+
raise "This version of Queue Classic does not support Postgres older than 9.6 (90600). This version is #{conn.server_version}. If you need that support, please use an older version."
|
97
|
+
end
|
98
|
+
|
84
99
|
conn.exec("SET application_name = '#{QC.app_name}'")
|
85
100
|
conn
|
86
101
|
end
|
@@ -92,7 +107,7 @@ module QC
|
|
92
107
|
[
|
93
108
|
host, # host or percent-encoded socket path
|
94
109
|
url.port || 5432,
|
95
|
-
nil,
|
110
|
+
nil, nil, #opts, tty
|
96
111
|
url.path.gsub("/",""), # database name
|
97
112
|
url.user,
|
98
113
|
url.password
|
@@ -106,6 +121,5 @@ module QC
|
|
106
121
|
raise(ArgumentError, "missing QC_DATABASE_URL or DATABASE_URL")
|
107
122
|
@db_url = URI.parse(url)
|
108
123
|
end
|
109
|
-
|
110
124
|
end
|
111
125
|
end
|