skiplock 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +26 -5
- data/lib/skiplock.rb +5 -4
- data/lib/skiplock/dispatcher.rb +40 -15
- data/lib/skiplock/job.rb +15 -4
- data/lib/skiplock/manager.rb +56 -27
- data/lib/skiplock/version.rb +1 -1
- metadata +2 -3
- data/lib/skiplock/notification.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8155870e392d0172d914c5e10d981560eb05af653603d331ce46cdd3419b2efa
|
4
|
+
data.tar.gz: 940699344273b928820c22307d6cea654d4bdad6debfa80c67fbb28dc8490ea9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa423c44556fb2a31cc2ec6cf9f25d6c9712b460920a0d39d0108ade11fa7738fe24e8f1857236cd0a67042ac6ced5cb0b1c34774e8946b72fe971e3202426f7
|
7
|
+
data.tar.gz: ac5456a0613ad3d94e574de100ee26dd018bee39c2a74c16237c798b873a45798519c33b08cb05a26ab18415e15b87252699e2b4bf1978fffbc521008fccdffe
|
data/README.md
CHANGED
@@ -54,7 +54,11 @@ The library is quite small compared to other PostgreSQL job queues (eg. *delay_j
|
|
54
54
|
min_threads: 1
|
55
55
|
max_threads: 5
|
56
56
|
max_retries: 20
|
57
|
+
notification: auto
|
57
58
|
purge_completion: true
|
59
|
+
queues:
|
60
|
+
default: 200
|
61
|
+
mailers: 100
|
58
62
|
workers: 0
|
59
63
|
```
|
60
64
|
Available configuration options are:
|
@@ -62,8 +66,10 @@ The library is quite small compared to other PostgreSQL job queues (eg. *delay_j
|
|
62
66
|
- **min_threads** (*integer*): sets minimum number of threads staying idle
|
63
67
|
- **max_threads** (*integer*): sets the maximum number of threads allowed to run jobs
|
64
68
|
- **max_retries** (*integer*): sets the maximum attempt a job will be retrying before it is marked expired (see Retry System for more details)
|
69
|
+
- **notification** (*enumeration*): sets the library to be used for notifying errors and exceptions (`auto, airbrake, bugsnag, exception_notification, false`)
|
65
70
|
- **purge_completion** (*boolean*): when set to **true** will delete jobs after they were completed successfully; if set to **false** then the completed jobs should be purged periodically to maximize performance (eg. clean up old jobs after 3 months)
|
66
|
-
- **
|
71
|
+
- **queues** (*hash*): defines the set of queues with priorites; lower priority takes precedence
|
72
|
+
- **workers** (*integer*) sets the maximum number of processes when running in standalone mode using the `skiplock` executable; setting this to **0** will enable **async mode**
|
67
73
|
|
68
74
|
#### Async mode
|
69
75
|
When **workers** is set to **0** then the jobs will be performed in the web server process using separate threads. If using multi-worker cluster web server like Puma, then it should be configured as below:
|
@@ -93,16 +99,22 @@ The library is quite small compared to other PostgreSQL job queues (eg. *delay_j
|
|
93
99
|
```
|
94
100
|
- Skiplock supports all ActiveJob features:
|
95
101
|
```ruby
|
96
|
-
MyJob.set(wait: 5.minutes, priority: 10).perform_later(1,2,3)
|
102
|
+
MyJob.set(queue: 'my_queue', wait: 5.minutes, priority: 10).perform_later(1,2,3)
|
97
103
|
```
|
98
104
|
- Outside of Rails application, queue the jobs by inserting the job records directly to the database table eg:
|
99
105
|
```sql
|
100
106
|
INSERT INTO skiplock.jobs(job_class) VALUES ('MyJob');
|
101
107
|
```
|
102
|
-
- Or with scheduling, priority and arguments:
|
108
|
+
- Or with scheduling, priority, queue and arguments:
|
103
109
|
```sql
|
104
|
-
INSERT INTO skiplock.jobs(job_class,priority,scheduled_at,data) VALUES ('MyJob',10,NOW()+INTERVAL '5 min','{"arguments":[1,2,3]}');
|
110
|
+
INSERT INTO skiplock.jobs(job_class,queue_name,priority,scheduled_at,data) VALUES ('MyJob','my_queue',10,NOW()+INTERVAL '5 min','{"arguments":[1,2,3]}');
|
105
111
|
```
|
112
|
+
## Queues priority vs Job priority
|
113
|
+
*Why do queues have priorities when jobs already have priorities?*
|
114
|
+
- Jobs are only prioritized with other jobs from the same queue
|
115
|
+
- Queues, on the other hand, are prioritized with other queues
|
116
|
+
- Rails has built-in queues that dispatches jobs without priorities (eg. Mail Delivery will queue as **mailers** with no priority)
|
117
|
+
|
106
118
|
## Cron system
|
107
119
|
`Skiplock` provides the capability to setup cron jobs for running tasks periodically. It fully supports the cron syntax to specify the frequency of the jobs. To setup a cron job, simply assign a valid cron schedule to the constant `CRON` for the Job Class.
|
108
120
|
- setup `MyJob` to run as cron job every hour at 30 minutes past
|
@@ -144,7 +156,16 @@ Once the retry attempt limit configured in ActiveJob has been reached, the contr
|
|
144
156
|
If the rescue blocks are not defined, then the built-in retry system of `skiplock` will kick in automatically. The retrying schedule is using an exponential formula (5 + 2**attempt). The `skiplock` configuration `max_retries` determines the the limit of attempts before the failing job is marked as expired. The maximum retry limit can be set as high as 20; this allows up to 12 days of retrying before the job is marked as expired.
|
145
157
|
|
146
158
|
## Notification system
|
147
|
-
|
159
|
+
`Skiplock` can use existing exception notification library to notify errors and exceptions. It supports `airbrake`, `bugsnag`, and `exception_notification`. A customized function can also be called whenever an exception occurs; this can be configured in an initializer as below:
|
160
|
+
```ruby
|
161
|
+
# config/initializers/skiplock.rb
|
162
|
+
Skiplock.on_error = -> (ex, previous = nil) do
|
163
|
+
if ex.backtrace != previous.try(:backtrace)
|
164
|
+
# sends custom email on new exceptions only
|
165
|
+
# the same repeated exceptions will only be sent once to avoid SPAM
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
148
169
|
|
149
170
|
## Contributing
|
150
171
|
|
data/lib/skiplock.rb
CHANGED
@@ -4,22 +4,23 @@ require 'active_record'
|
|
4
4
|
require 'skiplock/cron'
|
5
5
|
require 'skiplock/dispatcher'
|
6
6
|
require 'skiplock/manager'
|
7
|
-
require 'skiplock/notification'
|
8
7
|
require 'skiplock/job'
|
9
8
|
require 'skiplock/worker'
|
10
9
|
require 'skiplock/version'
|
11
10
|
|
12
11
|
module Skiplock
|
13
12
|
Settings = {
|
14
|
-
'logging' =>
|
13
|
+
'logging' => 'timestamp',
|
15
14
|
'min_threads' => 1,
|
16
15
|
'max_threads' => 5,
|
17
16
|
'max_retries' => 20,
|
17
|
+
'notification' => 'auto',
|
18
18
|
'purge_completion' => true,
|
19
19
|
'queues' => {
|
20
|
-
'default' =>
|
21
|
-
'mailers' =>
|
20
|
+
'default' => 200,
|
21
|
+
'mailers' => 100
|
22
22
|
},
|
23
23
|
'workers' => 0
|
24
24
|
}
|
25
|
+
mattr_accessor :on_error
|
25
26
|
end
|
data/lib/skiplock/dispatcher.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Skiplock
|
2
2
|
class Dispatcher
|
3
3
|
def initialize(master: true, worker_num: nil, worker_pids: [])
|
4
|
-
@queues_order_query =
|
4
|
+
@queues_order_query = Settings['queues'].map { |q,v| "WHEN queue_name = '#{q}' THEN #{v}" }.join(' ') if Settings['queues'].is_a?(Hash) && Settings['queues'].count > 0
|
5
5
|
@executor = Concurrent::ThreadPoolExecutor.new(min_threads: Settings['min_threads'], max_threads: Settings['max_threads'], max_queue: Settings['max_threads'], idletime: 60, auto_terminate: true, fallback_policy: :discard)
|
6
6
|
@master = master
|
7
7
|
if @master
|
@@ -17,19 +17,28 @@ module Skiplock
|
|
17
17
|
Thread.new do
|
18
18
|
Rails.application.reloader.wrap do
|
19
19
|
sleep(0.1) while @running && !Rails.application.initialized?
|
20
|
-
Process.setproctitle("skiplock-#{@master ? 'master' : 'worker[' + @worker_num.to_s + ']'}") if Settings['workers'] > 0
|
20
|
+
Process.setproctitle("skiplock-#{@master ? 'master[0]' : 'worker[' + @worker_num.to_s + ']'}") if Settings['workers'] > 0
|
21
21
|
ActiveRecord::Base.connection_pool.with_connection do |connection|
|
22
22
|
connection.exec_query('LISTEN "skiplock::jobs"')
|
23
|
-
hostname = `hostname`.strip
|
23
|
+
hostname = `hostname -f`.strip
|
24
24
|
@worker = Worker.create!(pid: Process.pid, ppid: (@master ? nil : Process.ppid), capacity: Settings['max_threads'], hostname: hostname)
|
25
25
|
if @master
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
if File.exists?('tmp/cache/skiplock')
|
27
|
+
# get performed jobs that could not sync with database
|
28
|
+
job_ids = File.read('tmp/cache/skiplock').split("\n")
|
29
|
+
if Settings['purge_completion']
|
30
|
+
Job.where(id: job_ids, running: true).delete_all
|
31
|
+
else
|
32
|
+
Job.where(id: job_ids, running: true).update_all(running: false, finished_at: File.mtime('tmp/cache/skiplock'))
|
33
|
+
end
|
34
|
+
File.delete('tmp/cache/skiplock')
|
32
35
|
end
|
36
|
+
# get current worker ids
|
37
|
+
worker_ids = Worker.where(hostname: hostname, pid: @worker_pids).ids
|
38
|
+
# reset orphaned jobs of the dead worker ids for retry
|
39
|
+
Job.where(running: true).where.not(worker_id: worker_ids).update_all(running: false, worker_id: nil)
|
40
|
+
# remove workers that were not shutdown properly on the host
|
41
|
+
Worker.where(hostname: hostname).where.not(pid: @worker_pids).delete_all
|
33
42
|
# reset retries schedules on startup
|
34
43
|
Job.where('scheduled_at > NOW() AND executions IS NOT NULL AND expired_at IS NULL AND finished_at IS NULL').update_all(scheduled_at: nil, updated_at: Time.now)
|
35
44
|
Cron.setup
|
@@ -46,6 +55,17 @@ module Skiplock
|
|
46
55
|
end
|
47
56
|
error = false
|
48
57
|
end
|
58
|
+
if Job::Errors.keys.count > 0
|
59
|
+
completed_ids = Job::Errors.keys.map { |k| k if Job::Errors[k] }.compact
|
60
|
+
if Settings['purge_completion'] && completed_ids.count > 0
|
61
|
+
Job.where(id: completed_ids, running: true).delete_all
|
62
|
+
elsif completed_ids.count > 0
|
63
|
+
Job.where(id: completed_ids, running: true).update_all(running: false, finished_at: Time.now)
|
64
|
+
end
|
65
|
+
orphaned_ids = Job::Errors.keys.map { |k| k unless Job::Errors[k] }.compact
|
66
|
+
Job.where(id: orphaned_ids, running: true).update_all(running: false, worker_id: nil, scheduled_at: (Time.now + 10)) if orphaned_ids.count > 0
|
67
|
+
Job::Errors.clear
|
68
|
+
end
|
49
69
|
if Time.now.to_f >= @next_schedule_at && @executor.remaining_capacity > 0
|
50
70
|
@executor.post { do_work }
|
51
71
|
end
|
@@ -59,7 +79,7 @@ module Skiplock
|
|
59
79
|
end
|
60
80
|
notifications.each do |n|
|
61
81
|
op, id, worker_id, queue_name, running, expired_at, finished_at, scheduled_at = n.split(',')
|
62
|
-
next if op == 'DELETE' || running == 'true' || expired_at || finished_at
|
82
|
+
next if op == 'DELETE' || running == 'true' || expired_at.to_s.length > 0 || finished_at.to_s.length > 0
|
63
83
|
if scheduled_at.to_f <= Time.now.to_f
|
64
84
|
@next_schedule_at = Time.now.to_f
|
65
85
|
elsif scheduled_at.to_f < @next_schedule_at
|
@@ -68,15 +88,18 @@ module Skiplock
|
|
68
88
|
end
|
69
89
|
end
|
70
90
|
rescue Exception => ex
|
71
|
-
|
91
|
+
STDERR.puts ex.message
|
92
|
+
STDERR.puts ex.backtrace
|
93
|
+
Skiplock.on_error.call(ex, @last_exception) if Skiplock.on_error.is_a?(Proc)
|
72
94
|
error = true
|
73
95
|
t = Time.now
|
74
96
|
while @running
|
75
97
|
sleep(0.5)
|
76
98
|
break if Time.now - t > 5
|
77
99
|
end
|
100
|
+
@last_exception = ex
|
78
101
|
end
|
79
|
-
sleep(0.
|
102
|
+
sleep(0.2)
|
80
103
|
end
|
81
104
|
connection.exec_query('UNLISTEN *')
|
82
105
|
end
|
@@ -100,9 +123,11 @@ module Skiplock
|
|
100
123
|
@next_schedule_at = result if result.is_a?(Float)
|
101
124
|
break
|
102
125
|
end
|
103
|
-
rescue Exception =>
|
104
|
-
puts
|
105
|
-
|
126
|
+
rescue Exception => ex
|
127
|
+
STDERR.puts ex.message
|
128
|
+
STDERR.puts ex.backtrace
|
129
|
+
Skiplock.on_error.call(ex, @last_exception) if Skiplock.on_error.is_a?(Proc)
|
130
|
+
@last_exception = ex
|
106
131
|
end
|
107
132
|
end
|
108
133
|
end
|
data/lib/skiplock/job.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Skiplock
|
2
2
|
class Job < ActiveRecord::Base
|
3
3
|
self.table_name = 'skiplock.jobs'
|
4
|
+
Errors = Concurrent::Map.new
|
4
5
|
|
5
6
|
# Return: Skiplock::Job if it was executed; otherwise returns the next Job's schedule time in FLOAT
|
6
7
|
def self.dispatch(queues_order_query: nil, worker_id: nil)
|
8
|
+
performed = false
|
7
9
|
self.connection.exec_query('BEGIN')
|
8
|
-
job = self.find_by_sql("SELECT id, scheduled_at FROM #{self.table_name} WHERE running = FALSE AND expired_at IS NULL AND finished_at IS NULL ORDER BY scheduled_at ASC NULLS FIRST,#{queues_order_query ? 'CASE ' + queues_order_query + ' ELSE NULL END ASC NULLS LAST,' : ''} priority ASC NULLS LAST, created_at ASC FOR UPDATE SKIP LOCKED LIMIT 1").first
|
10
|
+
job = self.find_by_sql("SELECT id, scheduled_at FROM #{self.table_name} WHERE running = FALSE AND expired_at IS NULL AND finished_at IS NULL ORDER BY scheduled_at ASC NULLS FIRST,#{queues_order_query ? ' CASE ' + queues_order_query + ' ELSE NULL END ASC NULLS LAST,' : ''} priority ASC NULLS LAST, created_at ASC FOR UPDATE SKIP LOCKED LIMIT 1").first
|
9
11
|
if job.nil? || job.scheduled_at.to_f > Time.now.to_f
|
10
12
|
self.connection.exec_query('END')
|
11
13
|
return (job ? job.scheduled_at.to_f : Float::INFINITY)
|
@@ -21,9 +23,9 @@ module Skiplock
|
|
21
23
|
ActiveJob::Base.execute(job_data)
|
22
24
|
rescue Exception => ex
|
23
25
|
end
|
26
|
+
performed = true
|
24
27
|
job.running = false
|
25
28
|
if ex
|
26
|
-
# TODO: report exception
|
27
29
|
job.exception_executions["[#{ex.class.name}]"] = (job.exception_executions["[#{ex.class.name}]"] || 0) + 1 unless job.exception_executions.key?('activejob_retry')
|
28
30
|
if job.executions >= Settings['max_retries'] || job.exception_executions.key?('activejob_retry')
|
29
31
|
job.expired_at = Time.now
|
@@ -32,11 +34,12 @@ module Skiplock
|
|
32
34
|
job.scheduled_at = Time.now + (5 * 2**job.executions)
|
33
35
|
job.save!
|
34
36
|
end
|
37
|
+
Skiplock.on_error.call(ex) if Skiplock.on_error.is_a?(Proc) && (job.executions % 3 == 1)
|
35
38
|
elsif job.exception_executions.key?('activejob_retry')
|
36
39
|
job.save!
|
37
|
-
elsif job
|
40
|
+
elsif job.cron
|
38
41
|
job.data['last_cron_run'] = Time.now.utc.to_s
|
39
|
-
next_cron_at = Cron.next_schedule_at(job
|
42
|
+
next_cron_at = Cron.next_schedule_at(job.cron)
|
40
43
|
if next_cron_at
|
41
44
|
job.executions = 1
|
42
45
|
job.exception_executions = nil
|
@@ -53,6 +56,14 @@ module Skiplock
|
|
53
56
|
job.save!
|
54
57
|
end
|
55
58
|
job
|
59
|
+
rescue Exception => ex
|
60
|
+
if performed
|
61
|
+
Errors[job.id] = true
|
62
|
+
File.write('tmp/cache/skiplock', job.id + "\n", mode: 'a')
|
63
|
+
else
|
64
|
+
Errors[job.id] = false
|
65
|
+
end
|
66
|
+
raise ex
|
56
67
|
ensure
|
57
68
|
Thread.current[:skiplock_dispatch_job] = nil
|
58
69
|
end
|
data/lib/skiplock/manager.rb
CHANGED
@@ -1,7 +1,21 @@
|
|
1
1
|
module Skiplock
|
2
2
|
class Manager
|
3
|
-
def self.start(standalone: false)
|
4
|
-
|
3
|
+
def self.start(standalone: false, workers: nil, max_retries: nil, max_threads: nil, min_threads: nil, logging: nil)
|
4
|
+
unless Settings.frozen?
|
5
|
+
load_settings
|
6
|
+
Settings['logging'] = logging if logging
|
7
|
+
Settings['max_retries'] = max_retries if max_retries
|
8
|
+
Settings['max_threads'] = max_threads if max_threads
|
9
|
+
Settings['min_threads'] = min_threads if min_threads
|
10
|
+
Settings['workers'] = workers if workers
|
11
|
+
Settings['max_retries'] = 20 if Settings['max_retries'] > 20
|
12
|
+
Settings['max_retries'] = 0 if Settings['max_retries'] < 0
|
13
|
+
Settings['max_threads'] = 1 if Settings['max_threads'] < 1
|
14
|
+
Settings['max_threads'] = 20 if Settings['max_threads'] > 20
|
15
|
+
Settings['min_threads'] = 0 if Settings['min_threads'] < 0
|
16
|
+
Settings['workers'] = 0 if Settings['workers'] < 0
|
17
|
+
Settings.freeze
|
18
|
+
end
|
5
19
|
return unless standalone || (caller.any?{|l| l =~ %r{/rack/}} && (Settings['workers'] == 0 || Rails.env.development?))
|
6
20
|
if standalone
|
7
21
|
self.standalone
|
@@ -22,37 +36,37 @@ module Skiplock
|
|
22
36
|
private
|
23
37
|
|
24
38
|
def self.load_settings
|
25
|
-
return if Settings.frozen?
|
26
39
|
config = YAML.load_file('config/skiplock.yml') rescue {}
|
27
40
|
Settings.merge!(config)
|
28
|
-
Settings['
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
41
|
+
Settings['queues'].values.each { |v| raise 'Queue value must be an integer' unless v.is_a?(Integer) } if Settings['queues'].is_a?(Hash)
|
42
|
+
case Settings['notification'].to_s.downcase
|
43
|
+
when 'auto'
|
44
|
+
if defined?(Airbrake)
|
45
|
+
Skiplock.on_error = -> (ex, previous = nil) { Airbrake.notify_sync(ex) unless ex.backtrace == previous.try(:backtrace) }
|
46
|
+
elsif defined?(Bugsnag)
|
47
|
+
Skiplock.on_error = -> (ex, previous = nil) { Bugsnag.notify(ex) unless ex.backtrace == previous.try(:backtrace) }
|
48
|
+
elsif defined?(ExceptionNotifier)
|
49
|
+
Skiplock.on_error = -> (ex, previous = nil) { ExceptionNotifier.notify_exception(ex) unless ex.backtrace == previous.try(:backtrace) }
|
50
|
+
else
|
51
|
+
puts "Unable to detect any known exception notification gem. Please define custom 'on_error' function and disable notification in 'config/skiplock.yml'"
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
when 'airbrake'
|
55
|
+
raise 'airbrake gem not found' unless defined?(Airbrake)
|
56
|
+
Skiplock.on_error = -> (ex, previous = nil) { Airbrake.notify_sync(ex) unless ex.backtrace == previous.try(:backtrace) }
|
57
|
+
when 'bugsnag'
|
58
|
+
raise 'bugsnag gem not found' unless defined?(Bugsnag)
|
59
|
+
Skiplock.on_error = -> (ex, previous = nil) { Bugsnag.notify(ex) unless ex.backtrace == previous.try(:backtrace) }
|
60
|
+
when 'exception_notification'
|
61
|
+
raise 'exception_notification gem not found' unless defined?(ExceptionNotifier)
|
62
|
+
Skiplock.on_error = -> (ex, previous = nil) { ExceptionNotifier.notify_exception(ex) unless ex.backtrace == previous.try(:backtrace) }
|
63
|
+
end
|
36
64
|
rescue Exception => e
|
37
65
|
STDERR.puts "Invalid configuration 'config/skiplock.yml': #{e.message}"
|
38
66
|
exit
|
39
67
|
end
|
40
68
|
|
41
69
|
def self.standalone
|
42
|
-
title = "Skiplock version: #{Skiplock::VERSION} (Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
|
43
|
-
puts "-"*(title.length)
|
44
|
-
puts title
|
45
|
-
puts "-"*(title.length)
|
46
|
-
puts "Additional workers: #{Settings['workers']}"
|
47
|
-
puts " Purge completion: #{Settings['purge_completion']}"
|
48
|
-
puts " Max retries: #{Settings['max_retries']}"
|
49
|
-
puts " Min threads: #{Settings['min_threads']}"
|
50
|
-
puts " Max threads: #{Settings['max_threads']}"
|
51
|
-
puts " Environment: #{Rails.env}"
|
52
|
-
puts " Logging: #{Settings['logging']}"
|
53
|
-
puts " Queues: #{Settings['queues'].map {|k,v| k + '(' + v.to_s + ')'}.join(', ')}"
|
54
|
-
puts " PID: #{Process.pid}"
|
55
|
-
puts "-"*(title.length)
|
56
70
|
if Settings['logging']
|
57
71
|
log_timestamp = (Settings['logging'].to_s == 'timestamp')
|
58
72
|
logfile = File.open('log/skiplock.log', 'a')
|
@@ -66,14 +80,29 @@ module Skiplock
|
|
66
80
|
Rails.logger.reopen('/dev/null')
|
67
81
|
Rails.logger.extend(ActiveSupport::Logger.broadcast(logger))
|
68
82
|
end
|
83
|
+
title = "Skiplock version: #{Skiplock::VERSION} (Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
|
84
|
+
puts "-"*(title.length)
|
85
|
+
puts title
|
86
|
+
puts "-"*(title.length)
|
87
|
+
puts "Purge completion: #{Settings['purge_completion']}"
|
88
|
+
puts " Notification: #{Settings['notification']}"
|
89
|
+
puts " Max retries: #{Settings['max_retries']}"
|
90
|
+
puts " Min threads: #{Settings['min_threads']}"
|
91
|
+
puts " Max threads: #{Settings['max_threads']}"
|
92
|
+
puts " Environment: #{Rails.env}"
|
93
|
+
puts " Logging: #{Settings['logging']}"
|
94
|
+
puts " Workers: #{Settings['workers']}"
|
95
|
+
puts " Queues: #{Settings['queues'].map {|k,v| k + '(' + v.to_s + ')'}.join(', ')}" if Settings['queues'].is_a?(Hash)
|
96
|
+
puts " PID: #{Process.pid}"
|
97
|
+
puts "-"*(title.length)
|
69
98
|
parent_id = Process.pid
|
70
99
|
shutdown = false
|
71
100
|
Signal.trap("INT") { shutdown = true }
|
72
101
|
Signal.trap("TERM") { shutdown = true }
|
73
102
|
worker_pids = []
|
74
|
-
Settings['workers'].times do |n|
|
103
|
+
(Settings['workers']-1).times do |n|
|
75
104
|
worker_pids << fork do
|
76
|
-
dispatcher = Dispatcher.new(master: false, worker_num: n)
|
105
|
+
dispatcher = Dispatcher.new(master: false, worker_num: n+1)
|
77
106
|
thread = dispatcher.run
|
78
107
|
loop do
|
79
108
|
sleep 0.5
|
data/lib/skiplock/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skiplock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tin Vo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -86,7 +86,6 @@ files:
|
|
86
86
|
- lib/skiplock/dispatcher.rb
|
87
87
|
- lib/skiplock/job.rb
|
88
88
|
- lib/skiplock/manager.rb
|
89
|
-
- lib/skiplock/notification.rb
|
90
89
|
- lib/skiplock/version.rb
|
91
90
|
- lib/skiplock/worker.rb
|
92
91
|
homepage: https://github.com/vtt/skiplock
|