cuetip 1.2.0
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 +7 -0
- data/bin/cuetip +50 -0
- data/lib/cuetip.rb +22 -0
- data/lib/cuetip/config.rb +47 -0
- data/lib/cuetip/engine.rb +7 -0
- data/lib/cuetip/job.rb +100 -0
- data/lib/cuetip/models/job.rb +135 -0
- data/lib/cuetip/models/queued_job.rb +45 -0
- data/lib/cuetip/serialized_hashie.rb +19 -0
- data/lib/cuetip/version.rb +5 -0
- data/lib/cuetip/worker.rb +87 -0
- data/lib/cuetip/worker_group.rb +54 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 80caddd838028973a0877c6a4b303d0b36b6ad6f5c98564ed865a60f41ce348a
|
4
|
+
data.tar.gz: 8b5a04b3537ff9a6bad21225ea11becb3ce5d2b2dd1e8c4f30cf8649a55f90d9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d4b32a2ec0ad43135fd41e9a81cccf217a6415058f43244972835d6f902b5b6ac54cedd547dad7643a0a7ca7852d7a469465b263d2f392d6ba53f191f824accc
|
7
|
+
data.tar.gz: e02bbcd49dac8eada655e0b86d5ce31d8e1f9bf6186e0e0bd14ff79cf2927102a4a3457b6e31fe624a0e486f9b18ca1041244efa57de618ec8e0e1ad16c80dda
|
data/bin/cuetip
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'cuetip'
|
5
|
+
require 'cuetip/config'
|
6
|
+
require 'cuetip/version'
|
7
|
+
require 'cuetip/worker_group'
|
8
|
+
require 'optparse'
|
9
|
+
|
10
|
+
$stdout.sync = true
|
11
|
+
$stderr.sync = true
|
12
|
+
|
13
|
+
options = {}
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.version = Cuetip::VERSION
|
16
|
+
opts.banner = 'Usage: cuetip [options]'
|
17
|
+
|
18
|
+
opts.on('-c', '--config PATH', 'The path to your cuetip config file') do |config|
|
19
|
+
options[:config] = config
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on('-h', '--help', 'Prints this help') do
|
23
|
+
puts opts
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on('-w NUMBER', 'The number of workers to run') do |i|
|
28
|
+
options[:quantity] = i.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on('-q', '--queues QUEUE1,QUEUE2', 'Queues that you wish to work on') do |queues|
|
32
|
+
options[:queues] = []
|
33
|
+
queues.split(/,/).uniq.each do |queue|
|
34
|
+
options[:queues] << queue
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end.parse!
|
38
|
+
|
39
|
+
if options[:config]
|
40
|
+
if File.file?(options[:config])
|
41
|
+
file = File.expand_path(options[:config])
|
42
|
+
require file
|
43
|
+
else
|
44
|
+
puts "Cuetip config file not found at #{options[:config]}"
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
worker = Cuetip::WorkerGroup.new(options[:quantity].to_i == 0 ? Cuetip.config.worker_threads : options[:quantity].to_i, options[:queues])
|
50
|
+
worker.start
|
data/lib/cuetip.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuetip'
|
4
|
+
require 'cuetip/config'
|
5
|
+
require 'cuetip/job'
|
6
|
+
require 'cuetip/version'
|
7
|
+
|
8
|
+
module Cuetip
|
9
|
+
def self.config
|
10
|
+
@config ||= Config.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.logger
|
14
|
+
config.logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure(&block)
|
18
|
+
block.call(config)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'cuetip/engine' if defined?(Rails)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext/numeric/bytes'
|
5
|
+
require 'active_support/core_ext/numeric/time'
|
6
|
+
|
7
|
+
module Cuetip
|
8
|
+
class Config
|
9
|
+
# The length of time between polling
|
10
|
+
def polling_interval
|
11
|
+
@polling_interval || 5
|
12
|
+
end
|
13
|
+
attr_writer :polling_interval
|
14
|
+
|
15
|
+
# The number of worker threads to run
|
16
|
+
def worker_threads
|
17
|
+
@worker_threads || 1
|
18
|
+
end
|
19
|
+
attr_writer :worker_threads
|
20
|
+
|
21
|
+
# Return the logger
|
22
|
+
def logger
|
23
|
+
@logger ||= Logger.new(STDOUT)
|
24
|
+
end
|
25
|
+
attr_writer :logger
|
26
|
+
|
27
|
+
# Define a job event callback
|
28
|
+
def on(event, &block)
|
29
|
+
callbacks[event.to_sym] ||= []
|
30
|
+
callbacks[event.to_sym] << block
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return all callbacks
|
34
|
+
def callbacks
|
35
|
+
@callbacks ||= Hash.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# Emit some callbacks
|
39
|
+
def emit(event, *args)
|
40
|
+
return unless callbacks[event.to_sym]
|
41
|
+
|
42
|
+
callbacks[event.to_sym].each do |callback|
|
43
|
+
callback.call(*args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/cuetip/job.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuetip/models/job'
|
4
|
+
|
5
|
+
module Cuetip
|
6
|
+
class Job
|
7
|
+
class << self
|
8
|
+
# The queue that this job should be executed on
|
9
|
+
def queue_name
|
10
|
+
@queue_name || 'default'
|
11
|
+
end
|
12
|
+
attr_writer :queue_name
|
13
|
+
|
14
|
+
# The maximum length of time (in seconds) that a job can run for
|
15
|
+
def maximum_execution_time
|
16
|
+
@maximum_execution_time || 12.hours
|
17
|
+
end
|
18
|
+
attr_writer :maximum_execution_time
|
19
|
+
|
20
|
+
# The maximum length of time (in seconds) between the job being created and it being run
|
21
|
+
def ttl
|
22
|
+
@ttl || 6.hours
|
23
|
+
end
|
24
|
+
attr_writer :ttl
|
25
|
+
|
26
|
+
# The maximum number of times this job can be run
|
27
|
+
def retry_count
|
28
|
+
@retry_count || 0
|
29
|
+
end
|
30
|
+
attr_writer :retry_count
|
31
|
+
|
32
|
+
# The maximum length of time (in seconds) between each execution of this job
|
33
|
+
def retry_interval
|
34
|
+
@retry_interval || 1.minute
|
35
|
+
end
|
36
|
+
attr_writer :retry_interval
|
37
|
+
|
38
|
+
# The length of time (in seconds) from when this job is queued to when it should be executed
|
39
|
+
def delay_execution
|
40
|
+
@delay_execution || 0
|
41
|
+
end
|
42
|
+
attr_writer :delay_execution
|
43
|
+
|
44
|
+
# Queue this job
|
45
|
+
#
|
46
|
+
# @param params [Hash]
|
47
|
+
# @return [Cuetip::Models::Job]
|
48
|
+
def queue(params = {}, &block)
|
49
|
+
# Create our new job
|
50
|
+
job = Models::Job.new(class_name: name, params: params)
|
51
|
+
# Copy over any class leve lconfig
|
52
|
+
job.queue_name = queue_name
|
53
|
+
job.maximum_execution_time = maximum_execution_time
|
54
|
+
job.ttl = ttl
|
55
|
+
job.retry_count = retry_count
|
56
|
+
job.retry_interval = retry_interval
|
57
|
+
job.delay_execution = delay_execution
|
58
|
+
# Call the block
|
59
|
+
block.call(job) if block_given?
|
60
|
+
# Create the job
|
61
|
+
job.save!
|
62
|
+
# Return the job
|
63
|
+
job
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Initialize this job instance by providing a queued job instance
|
68
|
+
#
|
69
|
+
# @param queued_job [Cuetip::Models::Job]
|
70
|
+
def initialize(job)
|
71
|
+
@job = job
|
72
|
+
end
|
73
|
+
|
74
|
+
# Perform a job
|
75
|
+
#
|
76
|
+
# @return [void]
|
77
|
+
def perform; end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Return all parameters for the job
|
82
|
+
#
|
83
|
+
# @return [Hashie::Mash]
|
84
|
+
def params
|
85
|
+
@job.params
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return the queued job object
|
89
|
+
#
|
90
|
+
# @return [Cuetip::Models::Job]
|
91
|
+
attr_reader :job
|
92
|
+
|
93
|
+
# Return a quick access for the job
|
94
|
+
#
|
95
|
+
# @return [Logger]
|
96
|
+
def logger
|
97
|
+
Cuetip.logger
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
require 'cuetip/models/queued_job'
|
5
|
+
require 'cuetip/serialized_hashie'
|
6
|
+
|
7
|
+
module Cuetip
|
8
|
+
module Models
|
9
|
+
class Job < ActiveRecord::Base
|
10
|
+
self.table_name = 'cuetip_jobs'
|
11
|
+
|
12
|
+
STATUSES = %w[Pending Running Complete Aborted Expired].freeze
|
13
|
+
|
14
|
+
has_one :queued_job, class_name: 'Cuetip::Models::QueuedJob'
|
15
|
+
belongs_to :associated_object, polymorphic: true, optional: true
|
16
|
+
|
17
|
+
serialize :params, Cuetip::SerializedHashie
|
18
|
+
|
19
|
+
before_validation(on: :create) do
|
20
|
+
self.status = 'Pending'
|
21
|
+
end
|
22
|
+
|
23
|
+
after_create do
|
24
|
+
# After creation, automatically add this job into the job queue for execution
|
25
|
+
create_queued_job!(run_after: run_after || delay_execution&.seconds&.from_now, queue_name: queue_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Is this job in the queue
|
29
|
+
def queued?
|
30
|
+
queued_job.present?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Has this job expired?
|
34
|
+
def expired?
|
35
|
+
ttl? ? expires_at <= Time.now : false
|
36
|
+
end
|
37
|
+
|
38
|
+
# The time that this job expired
|
39
|
+
def expires_at
|
40
|
+
ttl? ? created_at + ttl : nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Should this job be requeued on a failure right now?
|
44
|
+
def requeue_on_failure?
|
45
|
+
retry_count && retry_interval ? executions <= retry_count : false
|
46
|
+
end
|
47
|
+
|
48
|
+
# Remove this job from the queue
|
49
|
+
def remove_from_queue
|
50
|
+
queued_job&.destroy
|
51
|
+
self.queued_job = nil
|
52
|
+
log 'Removed from queue'
|
53
|
+
end
|
54
|
+
|
55
|
+
# Log some text about this job
|
56
|
+
#
|
57
|
+
# @param text [String]
|
58
|
+
def log(text)
|
59
|
+
Cuetip.logger.info "[#{id}] #{text}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Execute the job
|
63
|
+
#
|
64
|
+
# @return [Boolean] whether the job executed successfully or not
|
65
|
+
def execute(&block)
|
66
|
+
log "Beginning execution of job #{id} with #{class_name}"
|
67
|
+
# Initialize a new instance of the job we wish to execute
|
68
|
+
job_klass = class_name.constantize.new(self)
|
69
|
+
|
70
|
+
# If the job has expired, we should not be executing this so we'll just
|
71
|
+
# remove it from the queue and mark it as expired.
|
72
|
+
if expired?
|
73
|
+
log 'Job has expired'
|
74
|
+
self.status = 'Expired'
|
75
|
+
remove_from_queue
|
76
|
+
Cuetip.config.emit(:expired, self, job_klass)
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
|
80
|
+
Cuetip.config.emit(:before_perform, self, job_klass)
|
81
|
+
|
82
|
+
# If we have a block, call this so we can manipulate our actual job class
|
83
|
+
# before execution if needed (mostly for testing)
|
84
|
+
block.call(job_klass) if block_given?
|
85
|
+
|
86
|
+
# Mark the job as runnign
|
87
|
+
update!(status: 'Running', started_at: Time.now, executions: executions + 1)
|
88
|
+
|
89
|
+
begin
|
90
|
+
# Perform the job within a timeout
|
91
|
+
Timeout.timeout(maximum_execution_time || 1.year) do
|
92
|
+
job_klass.perform
|
93
|
+
end
|
94
|
+
# Mark the job as complete and remove it from the queue
|
95
|
+
self.status = 'Complete'
|
96
|
+
log 'Job completed successfully'
|
97
|
+
remove_from_queue
|
98
|
+
|
99
|
+
Cuetip.config.emit(:completed, self, job_klass)
|
100
|
+
|
101
|
+
true
|
102
|
+
rescue Exception, Timeout::TimeoutError => e
|
103
|
+
log "Job failed with #{e.class} (#{e.message})"
|
104
|
+
|
105
|
+
# If there's an error, mark the job as failed and copy exception
|
106
|
+
# data into the job
|
107
|
+
self.status = 'Failed'
|
108
|
+
self.exception_class = e.class.name
|
109
|
+
self.exception_message = e.message
|
110
|
+
self.exception_backtrace = e.backtrace.join("\n")
|
111
|
+
|
112
|
+
# Handle requeing the job if needed.
|
113
|
+
if requeue_on_failure?
|
114
|
+
# Requeue this job for execution again after the retry interval.
|
115
|
+
new_job = queued_job.requeue(run_after: Time.now + retry_interval.to_i)
|
116
|
+
log "Requeing job to run after #{new_job.run_after.to_s(:long)}"
|
117
|
+
self.status = 'Pending'
|
118
|
+
else
|
119
|
+
# We're done with this job. We can't do any more retries.
|
120
|
+
remove_from_queue
|
121
|
+
end
|
122
|
+
|
123
|
+
Cuetip.config.emit(:exception, e, self, job_klass)
|
124
|
+
|
125
|
+
false
|
126
|
+
end
|
127
|
+
ensure
|
128
|
+
self.finished_at = Time.now
|
129
|
+
save!
|
130
|
+
Cuetip.config.emit(:finished, self, job_klass)
|
131
|
+
log 'Finished processing'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'active_record'
|
5
|
+
require 'cuetip/models/job'
|
6
|
+
|
7
|
+
module Cuetip
|
8
|
+
module Models
|
9
|
+
class QueuedJob < ActiveRecord::Base
|
10
|
+
PROCESS_IDENTIFIER = Socket.gethostname + ":#{Process.pid}"
|
11
|
+
self.table_name = 'cuetip_job_queue'
|
12
|
+
|
13
|
+
scope :pending, -> { where(locked_at: nil).where('run_after is null or run_after < ?', Time.now) }
|
14
|
+
scope :from_queues, -> (queues) { where(queue_name: queues) }
|
15
|
+
|
16
|
+
belongs_to :job, class_name: 'Cuetip::Models::Job'
|
17
|
+
|
18
|
+
# Unlock the job and allow it to be re-run elsewhere.
|
19
|
+
def requeue(attributes = {})
|
20
|
+
self.attributes = attributes
|
21
|
+
self.locked_by = nil
|
22
|
+
self.locked_at = nil
|
23
|
+
save!
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
# Generate a random lock ID to use in the locking process
|
28
|
+
def self.generate_lock_id
|
29
|
+
PROCESS_IDENTIFIER + ':' + rand(1_000_000_000).to_s.rjust(9, '0')
|
30
|
+
end
|
31
|
+
|
32
|
+
# Simultaneously find an outstanding job and lock it
|
33
|
+
def self.find_and_lock(queued_job_id = nil)
|
34
|
+
lock_id = generate_lock_id
|
35
|
+
scope = if queued_job_id
|
36
|
+
where(id: queued_job_id)
|
37
|
+
else
|
38
|
+
self
|
39
|
+
end
|
40
|
+
count = scope.pending.limit(1).update_all(locked_by: lock_id, locked_at: Time.now)
|
41
|
+
QueuedJob.find_by_locked_by(lock_id) if count > 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hashie/mash'
|
4
|
+
|
5
|
+
module Cuetip
|
6
|
+
class SerializedHashie < Hashie::Mash
|
7
|
+
def self.dump(obj)
|
8
|
+
obj.reject! { |_k, v| v.blank? }
|
9
|
+
obj.each do |key, value|
|
10
|
+
obj[key] = value.reject(&:blank?) if value.is_a?(Array)
|
11
|
+
end
|
12
|
+
ActiveSupport::JSON.encode(obj.to_h)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.load(raw_hash)
|
16
|
+
new(JSON.parse(raw_hash || '{}'))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuetip/models/queued_job'
|
4
|
+
|
5
|
+
module Cuetip
|
6
|
+
class Worker
|
7
|
+
attr_reader :status
|
8
|
+
|
9
|
+
include ActiveSupport::Callbacks
|
10
|
+
|
11
|
+
define_callbacks :execute, :poll
|
12
|
+
|
13
|
+
def initialize(group, id, queues)
|
14
|
+
@group = group
|
15
|
+
@id = id
|
16
|
+
@queues = queues
|
17
|
+
end
|
18
|
+
|
19
|
+
def request_exit!
|
20
|
+
@exit_requested = true
|
21
|
+
interrupt_sleep
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
set_status('idle')
|
26
|
+
loop do
|
27
|
+
unless run_once
|
28
|
+
interruptible_sleep(Cuetip.config.polling_interval + rand)
|
29
|
+
end
|
30
|
+
|
31
|
+
break if @exit_requested
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def run_once
|
36
|
+
set_status('polling')
|
37
|
+
run_callbacks :poll do
|
38
|
+
queued_job = silence do
|
39
|
+
if @queues.any?
|
40
|
+
scope = Cuetip::Models::QueuedJob.from_queues(@queues)
|
41
|
+
else
|
42
|
+
scope = Cuetip::Models::QueuedJob
|
43
|
+
end
|
44
|
+
scope.find_and_lock
|
45
|
+
end
|
46
|
+
|
47
|
+
if queued_job
|
48
|
+
set_status("executing #{queued_job.job.id}")
|
49
|
+
run_callbacks :execute do
|
50
|
+
queued_job.job.execute
|
51
|
+
end
|
52
|
+
set_status('idle')
|
53
|
+
true
|
54
|
+
else
|
55
|
+
set_status('idle')
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def set_status(status)
|
64
|
+
@status = status
|
65
|
+
@group&.set_process_name
|
66
|
+
end
|
67
|
+
|
68
|
+
def interruptible_sleep(seconds)
|
69
|
+
sleep_check, @sleep_interrupt = IO.pipe
|
70
|
+
IO.select([sleep_check], nil, nil, seconds)
|
71
|
+
sleep_check.close
|
72
|
+
@sleep_interrupt.close
|
73
|
+
end
|
74
|
+
|
75
|
+
def interrupt_sleep
|
76
|
+
@sleep_interrupt&.close
|
77
|
+
end
|
78
|
+
|
79
|
+
def silence(&block)
|
80
|
+
if ActiveRecord::Base.logger
|
81
|
+
ActiveRecord::Base.logger.silence(&block)
|
82
|
+
else
|
83
|
+
block.call
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuetip/worker'
|
4
|
+
|
5
|
+
module Cuetip
|
6
|
+
class WorkerGroup
|
7
|
+
include ActiveSupport::Callbacks
|
8
|
+
|
9
|
+
define_callbacks :run_worker
|
10
|
+
|
11
|
+
attr_reader :quantity
|
12
|
+
attr_reader :workers
|
13
|
+
attr_reader :threads
|
14
|
+
|
15
|
+
def initialize(quantity, queues)
|
16
|
+
@quantity = quantity
|
17
|
+
@queues = queues || []
|
18
|
+
@workers = {}
|
19
|
+
@threads = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
Cuetip.logger.info "Starting #{@quantity} Cuetip workers"
|
24
|
+
if @queues.any?
|
25
|
+
@queues.each { |q| Cuetip.logger.info "-> Joined queue: #{q.to_s}" }
|
26
|
+
end
|
27
|
+
|
28
|
+
exit_trap = proc do
|
29
|
+
@workers.each { |_, worker| worker.request_exit! }
|
30
|
+
puts 'Exiting...'
|
31
|
+
end
|
32
|
+
|
33
|
+
trap('INT', &exit_trap)
|
34
|
+
trap('TERM', &exit_trap)
|
35
|
+
|
36
|
+
@quantity.times do |i|
|
37
|
+
@workers[i] = Worker.new(self, i, @queues)
|
38
|
+
Cuetip.logger.info "-> Starting worker #{i}"
|
39
|
+
@threads[i] = Thread.new(@workers[i]) do |worker|
|
40
|
+
run_callbacks :run_worker do
|
41
|
+
worker.run
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@threads[i].abort_on_exception = true
|
45
|
+
end
|
46
|
+
@threads.values.each(&:join)
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_process_name
|
50
|
+
thread_names = @workers.values.map(&:status)
|
51
|
+
Process.setproctitle("Cuetip: #{thread_names.inspect}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cuetip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Cooke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hashie
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: An ActiveRecord job queueing system
|
42
|
+
email:
|
43
|
+
- me@adamcooke.io
|
44
|
+
executables:
|
45
|
+
- cuetip
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- bin/cuetip
|
50
|
+
- lib/cuetip.rb
|
51
|
+
- lib/cuetip/config.rb
|
52
|
+
- lib/cuetip/engine.rb
|
53
|
+
- lib/cuetip/job.rb
|
54
|
+
- lib/cuetip/models/job.rb
|
55
|
+
- lib/cuetip/models/queued_job.rb
|
56
|
+
- lib/cuetip/serialized_hashie.rb
|
57
|
+
- lib/cuetip/version.rb
|
58
|
+
- lib/cuetip/worker.rb
|
59
|
+
- lib/cuetip/worker_group.rb
|
60
|
+
homepage: https://github.com/adamcooke/cuetip
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubygems_version: 3.0.3
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: An ActiveRecord job queueing system
|
83
|
+
test_files: []
|