rabbit_jobs 0.11.5 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbaa1fdb2d8e1c9716955755efa130be1eee820e
4
- data.tar.gz: f2b6a65de1baff5a6b4696344ac4fe8d7bc5472c
3
+ metadata.gz: 41fb778c890aee7f7a0d1a7c7912abbbf58cb1eb
4
+ data.tar.gz: dbb37f7b51818faa4a1855a16cf2ecdea843d92f
5
5
  SHA512:
6
- metadata.gz: 0cd1995fc29516e21c31b0cdd5993e0184f06b25eef129d095e39cd83298c89d57206d795023ae21e22c817f947877a9cdedd075ab207e93062b29e99af47924
7
- data.tar.gz: dd3ebbf992e689b3afabb00803b7159b89bb9088071b757c38ea3d4174478601ba234c7f2ee440d438768754f990312964cc1dd58242f026b068d82b9c570e63
6
+ metadata.gz: 42debf0e98af814b76c6b00782645f771e9cc9fb1de85199521ec7b315305745a4023fec0bcf7ff66a14ff21145d9d9656f2e30a2d39d0b67511bccdfa5dcb58
7
+ data.tar.gz: 4a8a03c5fbfccfcf31f71ae0668cec20f2ae61a6ac12e8d5d43cf372e959d3bbbebe236cdfb7dc4e029b03d8d31288172acf12bbb055c650840b544fb2b7e184
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
data/build CHANGED
@@ -1,9 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # -*- coding: utf-8 -*-
3
2
  require 'fileutils'
4
3
 
5
- abort("rspec tests failed.") unless system("bundle install")
6
- abort("rspec tests failed.") unless system("COVERAGE=true && bundle exec rspec")
7
-
8
- coverage_dir = File.expand_path('../coverage', __FILE__)
9
- FileUtils.move(coverage_dir, ENV['CC_BUILD_ARTIFACTS']) if ENV['CC_BUILD_ARTIFACTS']
4
+ abort('bundle install failed') unless system('bundle install')
5
+ abort('rspec tests failed.') unless system('bundle exec rspec')
data/examples/client CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- # -*- encoding : utf-8 -*-
3
2
 
4
3
  require 'bundler'
5
4
  Bundler.setup
@@ -13,7 +12,7 @@ class MyCurrentJob
13
12
  end
14
13
 
15
14
  RJ.configure { |c|
16
- c.queue "mandarin", durable: true, auto_delete: false, ack: true, arguments: {'x-ha-policy' => 'all'}
15
+ c.queue "mandarin", durable: true, auto_delete: false, manual_ack: true, arguments: {'x-ha-policy' => 'all'}
17
16
  c.server "amqp://localhost/rj"
18
17
  }
19
18
 
@@ -6,9 +6,9 @@ require 'json'
6
6
  RabbitJobs.configure do |c|
7
7
  c.server "amqp://localhost/"
8
8
 
9
- c.queue 'rabbit_jobs_test1', durable: true, auto_delete: false, ack: true, arguments: {'x-ha-policy' => 'all'}
10
- c.queue 'rabbit_jobs_test2', durable: true, auto_delete: false, ack: true, arguments: {'x-ha-policy' => 'all'}
11
- c.queue 'rabbit_jobs_test3', durable: true, auto_delete: false, ack: true, arguments: {'x-ha-policy' => 'all'}
9
+ c.queue 'rabbit_jobs_test1', durable: true, auto_delete: false, manual_ack: true, arguments: {'x-ha-policy' => 'all'}
10
+ c.queue 'rabbit_jobs_test2', durable: true, auto_delete: false, manual_ack: true, arguments: {'x-ha-policy' => 'all'}
11
+ c.queue 'rabbit_jobs_test3', durable: true, auto_delete: false, manual_ack: true, arguments: {'x-ha-policy' => 'all'}
12
12
  end
13
13
 
14
14
  puts JSON.pretty_generate(RabbitJobs.config.to_hash)
data/examples/worker CHANGED
@@ -14,7 +14,7 @@ class MyCurrentJob
14
14
  end
15
15
 
16
16
  RJ.configure { |c|
17
- c.queue "mandarin", durable: true, auto_delete: false, ack: true, arguments: {'x-ha-policy' => 'all'}
17
+ c.queue "mandarin", durable: true, auto_delete: false, manual_ack: true, arguments: {'x-ha-policy' => 'all'}
18
18
  c.server "amqp://localhost/rj"
19
19
  }
20
20
 
data/lib/rabbit_jobs.rb CHANGED
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  require 'logger'
3
2
  require 'json'
4
3
  require 'bunny'
@@ -11,6 +10,7 @@ require 'active_support/core_ext/module/delegation'
11
10
 
12
11
  require 'rabbit_jobs/version'
13
12
  require 'rabbit_jobs/configuration'
13
+ require 'rabbit_jobs/amqp_transport'
14
14
  require 'rabbit_jobs/consumer/job_consumer'
15
15
  require 'rabbit_jobs/job'
16
16
  require 'rabbit_jobs/publisher'
@@ -19,57 +19,67 @@ require 'rabbit_jobs/worker'
19
19
  require 'rabbit_jobs/scheduler'
20
20
  require 'rabbit_jobs/tasks'
21
21
 
22
+ # Public gem API.
22
23
  module RabbitJobs
23
- extend self
24
+ class << self
25
+ delegate :publish_to, :direct_publish_to, :purge_queue, :queue_status, to: Publisher
24
26
 
25
- def publish_to(routing_key, klass, *params)
26
- Publisher.publish_to(routing_key, klass, *params)
27
- end
27
+ attr_writer :logger
28
+ def logger
29
+ unless @logger
30
+ @logger = Logger.new($stdout)
31
+ @logger.level = Logger::INFO
32
+ @logger.formatter = nil
33
+ @logger.progname = 'rj'
34
+ end
35
+ @logger
36
+ end
28
37
 
29
- def direct_publish_to(routing_key, payload, ex = {})
30
- Publisher.direct_publish_to(routing_key, payload, ex)
31
- end
38
+ def before_process_message(&block)
39
+ fail unless block_given?
40
+ @before_process_message_callbacks ||= []
41
+ @before_process_message_callbacks << block
42
+ end
32
43
 
33
- def purge_queue(*routing_keys)
34
- Publisher.purge_queue(*routing_keys)
35
- end
44
+ def run_before_process_message_callbacks
45
+ @before_process_message_callbacks ||= []
46
+ @before_process_message_callbacks.each do |callback|
47
+ return false unless callback.call
48
+ end
49
+ true
50
+ rescue
51
+ false
52
+ end
36
53
 
37
- attr_writer :logger
38
- def logger
39
- unless @logger
40
- @logger = Logger.new($stdout)
41
- @logger.level = Logger::INFO
42
- @logger.formatter = nil
43
- @logger.progname = 'rj'
54
+ # Configuration
55
+ def configure
56
+ @configuration ||= Configuration.new
57
+ yield @configuration if block_given?
44
58
  end
45
- @logger
46
- end
47
59
 
48
- def after_fork(&block)
49
- raise unless block_given?
50
- @_after_fork_callbacks ||= []
51
- @_after_fork_callbacks << block
52
- end
60
+ def config
61
+ @configuration ||= load_config
62
+ end
53
63
 
54
- def _run_after_fork_callbacks
55
- @_after_fork_callbacks ||= []
56
- @_after_fork_callbacks.each { |callback|
57
- callback.call
58
- }
59
- end
64
+ def load_config(config_file = nil)
65
+ @configuration ||= nil
60
66
 
61
- def before_process_message(&block)
62
- raise unless block_given?
63
- @before_process_message_callbacks ||= []
64
- @before_process_message_callbacks << block
65
- end
67
+ config_file ||= defined?(Rails) && Rails.respond_to?(:root) && Rails.root.join('config/rabbit_jobs.yml')
68
+ if config_file
69
+ if File.exist?(config_file)
70
+ @configuration ||= Configuration.new
71
+ @configuration.load_file(config_file)
72
+ end
73
+ end
74
+
75
+ unless @configuration
76
+ configure do |c|
77
+ c.server 'amqp://localhost'
78
+ end
79
+ end
66
80
 
67
- def run_before_process_message_callbacks
68
- @before_process_message_callbacks ||= []
69
- @before_process_message_callbacks.each { |callback|
70
- return false unless callback.call
71
- }
72
- return true
81
+ @configuration
82
+ end
73
83
  end
74
84
  end
75
85
 
@@ -0,0 +1,33 @@
1
+ module RabbitJobs
2
+ # Connection manager.
3
+ module AmqpTransport
4
+ class << self
5
+ def amqp_connection
6
+ @amqp_connection ||= Bunny.new(
7
+ RabbitJobs.config.server,
8
+ automatically_recover: false,
9
+ properties: Bunny::Session::DEFAULT_CLIENT_PROPERTIES.merge(product: "rabbit_jobs #{Process.pid}")
10
+ ).start
11
+ end
12
+
13
+ def publisher_channel
14
+ @publisher_channel ||= amqp_connection.create_channel(2)
15
+ end
16
+
17
+ def consumer_channel
18
+ @consumer_channel ||= amqp_connection.create_channel(1)
19
+ end
20
+
21
+ def amqp_cleanup
22
+ conn = @amqp_connection
23
+ @amqp_connection = nil
24
+
25
+ conn.stop if conn && conn.status != :not_connected
26
+ @consumer_channel.work_pool.join if @consumer_channel
27
+ @publisher_channel = nil
28
+ @consumer_channel = nil
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,37 +1,5 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module RabbitJobs
3
-
4
- extend self
5
-
6
- def configure
7
- @@configuration ||= Configuration.new
8
- yield @@configuration if block_given?
9
- end
10
-
11
- def config
12
- @@configuration ||= load_config
13
- end
14
-
15
- def load_config(config_file = nil)
16
- @@configuration ||= nil
17
-
18
- config_file ||= defined?(Rails) && Rails.respond_to?(:root) && Rails.root.join('config/rabbit_jobs.yml')
19
- if config_file
20
- if File.exists?(config_file)
21
- @@configuration ||= Configuration.new
22
- @@configuration.load_file(config_file)
23
- end
24
- end
25
-
26
- unless @@configuration
27
- self.configure do |c|
28
- c.server "amqp://localhost"
29
- end
30
- end
31
-
32
- @@configuration
33
- end
34
-
2
+ # Configuration DSL.
35
3
  class Configuration
36
4
  DEFAULT_EXCHANGE_PARAMS = {
37
5
  auto_delete: false,
@@ -42,7 +10,7 @@ module RabbitJobs
42
10
  auto_delete: false,
43
11
  exclusive: false,
44
12
  durable: true,
45
- ack: true
13
+ manual_ack: true
46
14
  }
47
15
 
48
16
  DEFAULT_MESSAGE_PARAMS = {
@@ -59,7 +27,9 @@ module RabbitJobs
59
27
  @data = {
60
28
  error_log: true,
61
29
  server: 'amqp://localhost',
62
- queues: {}
30
+ queues: {
31
+ jobs: DEFAULT_QUEUE_PARAMS
32
+ }
63
33
  }
64
34
  end
65
35
 
@@ -67,14 +37,6 @@ module RabbitJobs
67
37
  @data[name]
68
38
  end
69
39
 
70
- def default_queue(value = nil)
71
- if value
72
- @default_queue = value.to_sym
73
- else
74
- @default_queue || RJ.config[:queues].keys.first || :jobs
75
- end
76
- end
77
-
78
40
  def error_log
79
41
  @data[:error_log]
80
42
  end
@@ -89,8 +51,8 @@ module RabbitJobs
89
51
  end
90
52
 
91
53
  def queue(name, params = {})
92
- raise ArgumentError.new("name is #{name.inspect}") unless name && name.is_a?(String) && name != ""
93
- raise ArgumentError.new("params is #{params.inspect}") unless params && params.is_a?(Hash)
54
+ fail ArgumentError, "name is #{name.inspect}" unless name && name.is_a?(String) && name != ''
55
+ fail ArgumentError, "params is #{params.inspect}" unless params && params.is_a?(Hash)
94
56
 
95
57
  name = name.downcase.to_sym
96
58
 
@@ -105,6 +67,10 @@ module RabbitJobs
105
67
  @data[:queues].keys
106
68
  end
107
69
 
70
+ def queue?(routing_key)
71
+ routing_keys.include?(routing_key.to_sym)
72
+ end
73
+
108
74
  def load_file(filename)
109
75
  load_yaml(File.read(filename))
110
76
  end
@@ -116,9 +82,9 @@ module RabbitJobs
116
82
  def convert_yaml_config(yaml)
117
83
  yaml = parse_environment(yaml)
118
84
 
119
- @data = {queues: {}}
120
- %w(server default_queue).each do |m|
121
- self.send(m, yaml[m])
85
+ @data = { queues: {} }
86
+ %w(server).each do |m|
87
+ send(m, yaml[m])
122
88
  end
123
89
  yaml['queues'].each do |name, params|
124
90
  queue name, params.symbolize_keys || {}
@@ -128,9 +94,7 @@ module RabbitJobs
128
94
  private
129
95
 
130
96
  def parse_environment(yaml)
131
- yaml['rabbit_jobs'] ||
132
- (defined?(Rails) && yaml[Rails.env.to_s]) ||
133
- yaml
97
+ yaml['rabbit_jobs'] || (defined?(Rails) && yaml[Rails.env.to_s]) || yaml
134
98
  end
135
99
  end
136
100
  end
@@ -1,32 +1,22 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module RabbitJobs
3
2
  module Consumer
3
+ # Default job consumer.
4
4
  class JobConsumer
5
- def process_message(delivery_info, properties, payload)
6
- job, *error_args = RJ::Job.parse(payload)
5
+ def process_message(_delivery_info, _properties, payload)
6
+ job, params = RJ::Job.parse(payload)
7
7
 
8
8
  if job.is_a?(Symbol)
9
- report_error(job, *error_args)
9
+ report_error(job, *params)
10
10
  else
11
11
  if job.expired?
12
- RJ.logger.warn "Job expired: #{job.to_ruby_string}"
12
+ RJ.logger.warn "Job expired: #{job.to_ruby_string(*params)}"
13
13
  else
14
- job.run_perform
14
+ job.send(:run_perform, *params)
15
15
  end
16
16
  end
17
17
  true
18
18
  end
19
19
 
20
- def log_airbrake(msg_or_exception, payload)
21
- if defined?(Airbrake)
22
- if msg_or_exception.is_a?(String)
23
- Airbrake.notify(RuntimeError.new(msg_or_exception))
24
- else
25
- Airbrake.notify(msg_or_exception)
26
- end
27
- end
28
- end
29
-
30
20
  def report_error(error_type, *args)
31
21
  case error_type
32
22
  when :not_found
@@ -40,4 +30,4 @@ module RabbitJobs
40
30
  end
41
31
  end
42
32
  end
43
- end
33
+ end
@@ -1,162 +1,137 @@
1
- # -*- encoding : utf-8 -*-
2
1
  require 'benchmark'
3
2
 
4
3
  module RabbitJobs
4
+ # Module to include in client jobs.
5
5
  module Job
6
- extend self
6
+ attr_accessor :created_at
7
7
 
8
- def self.included(base)
9
- base.extend (ClassMethods)
8
+ def expired?
9
+ exp_in = self.class.expires_in.to_i
10
+ return false if exp_in == 0 || created_at.nil?
10
11
 
11
- def initialize(*perform_params)
12
- self.params = perform_params
13
- self.opts = {}
14
- end
15
-
16
- attr_accessor :params, :opts
17
-
18
- def run_perform
19
- begin
20
- ret = nil
21
- execution_time = Benchmark.measure { ret = perform(*params) }
22
- RabbitJobs.logger.info short_message: "Completed: #{self.to_ruby_string}", _execution_time: execution_time.to_s.strip
23
- rescue ScriptError, StandardError
24
- log_job_error($!)
25
- run_on_error_hooks($!)
26
- end
27
- end
28
-
29
- def run_on_error_hooks(error)
30
- if self.class.rj_on_error_hooks
31
- self.class.rj_on_error_hooks.each do |proc_or_symbol|
32
- proc = proc_or_symbol
33
- if proc_or_symbol.is_a?(Symbol)
34
- proc = self.method(proc_or_symbol)
35
- end
12
+ Time.now.to_i > created_at + exp_in
13
+ end
36
14
 
37
- begin
38
- case proc.arity
39
- when 0
40
- proc.call()
41
- when 1
42
- proc.call(error)
43
- else
44
- proc.call(error, *params)
45
- end
46
- rescue
47
- RJ.logger.error($!)
48
- end
49
- end
50
- end
51
- end
15
+ def to_ruby_string(*params)
16
+ rs = self.class.name + params_string(*params)
17
+ rs << ", created_at: #{created_at}" if created_at
18
+ rs
19
+ end
52
20
 
53
- def payload
54
- {'class' => self.class.to_s, 'opts' => (self.opts || {}), 'params' => params}.to_json
55
- end
21
+ private
56
22
 
57
- def expires_in
58
- self.class.rj_expires_in
23
+ def params_string(*params)
24
+ if params.count > 0
25
+ "(#{params.map(&:to_s).join(', ')})"
26
+ else
27
+ ''
59
28
  end
29
+ end
60
30
 
61
- def expires?
62
- self.expires_in && self.expires_in > 0
63
- end
31
+ def log_job_error(error, *params)
32
+ RabbitJobs.logger.error(
33
+ short_message: (error.message.presence || 'rj_worker job error'),
34
+ _job: to_ruby_string,
35
+ _exception: error.class,
36
+ full_message: error.backtrace.join("\r\n"))
64
37
 
65
- def expires_at_expired?
66
- expires_at = opts['expires_at'].to_i
67
- return false if expires_at == 0
68
- Time.now.to_i > expires_at
69
- end
38
+ Airbrake.notify(error, session: { args: to_ruby_string(*params) }) if defined?(Airbrake)
39
+ end
70
40
 
71
- def expires_in_expired?
72
- exp_in = self.expires_in.to_i
73
- created_at = opts['created_at'].to_i
74
- return false if exp_in == 0 || created_at == 0
41
+ def run_perform(*params)
42
+ ret = nil
43
+ execution_time = Benchmark.measure { ret = perform(*params) }
44
+ RabbitJobs.logger.info(
45
+ short_message: "Completed: #{to_ruby_string(*params)}",
46
+ _execution_time: execution_time.to_s.strip)
47
+ rescue ScriptError, StandardError
48
+ log_job_error($!, *params)
49
+ run_on_error_hooks($!, *params)
50
+ end
75
51
 
76
- Time.now.to_i > created_at + exp_in
77
- end
52
+ def run_on_error_hooks(error, *params)
53
+ return unless @@rj_on_error_hooks.try(:present?)
78
54
 
79
- def expired?
80
- expires_at_expired? || expires_in_expired?
81
- end
55
+ @@rj_on_error_hooks.each do |proc_or_symbol|
56
+ proc = if proc_or_symbol.is_a?(Symbol)
57
+ method(proc_or_symbol)
58
+ else
59
+ proc_or_symbol
60
+ end
82
61
 
83
- def to_ruby_string
84
- rs = self.class.name
85
- rs << params_string
86
- if opts.count > 0
87
- rs << ", opts: "
88
- rs << opts.inspect
62
+ begin
63
+ case proc.arity
64
+ when 0
65
+ proc.call
66
+ when 1
67
+ proc.call(error)
68
+ else
69
+ proc.call(error, *params)
70
+ end
71
+ rescue
72
+ RJ.logger.error($!)
89
73
  end
90
74
  end
75
+ end
91
76
 
92
- def params_string
93
- if params.count > 0
94
- "(#{params.map(&:to_s).join(", ")})"
95
- else
96
- ""
97
- end
77
+ class << self
78
+ def parse(payload)
79
+ encoded = JSON.parse(payload)
80
+ job_klass = encoded['class'].to_s.constantize
81
+ job = job_klass.new
82
+ job.created_at = encoded['created_at']
83
+ [job, encoded['params']]
84
+ rescue NameError
85
+ [:not_found, encoded['class']]
86
+ rescue JSON::ParserError
87
+ [:parsing_error, payload]
88
+ rescue
89
+ [:error, $!, payload]
98
90
  end
99
91
 
100
- def log_job_error(error)
101
- RabbitJobs.logger.error(short_message: (error.message.presence || "rj_worker job error"),
102
- _job: self.to_ruby_string, _exception: error.class, full_message: error.backtrace.join("\r\n"))
103
-
104
- Airbrake.notify(error, session: {args: self.to_ruby_string}) if defined?(Airbrake)
92
+ def serialize(klass_name, *params)
93
+ {
94
+ 'class' => klass_name.to_s,
95
+ 'created_at' => Time.now.to_i,
96
+ 'params' => params
97
+ }.to_json
105
98
  end
106
- end
107
99
 
108
- module ClassMethods
109
- attr_accessor :rj_expires_in, :rj_on_error_hooks
100
+ def included(base)
101
+ base.extend(ClassMethods)
102
+ base.queue(:jobs)
103
+ end
110
104
 
111
105
  # DSL method for jobs
112
- def expires_in(seconds)
113
- @rj_expires_in = seconds.to_i
114
- end
106
+ module ClassMethods
107
+ def expires_in(seconds = nil)
108
+ @expires_in = seconds.to_i if seconds
109
+ @expires_in
110
+ end
115
111
 
116
- def on_error(*hooks)
117
- hooks.each do |proc_or_symbol|
118
- raise ArgumentError.new("Pass proc or symbol to on_error hook") unless proc_or_symbol && ( proc_or_symbol.is_a?(Proc) || proc_or_symbol.is_a?(Symbol) )
112
+ def on_error(*hooks)
119
113
  @rj_on_error_hooks ||= []
120
- @rj_on_error_hooks << proc_or_symbol
114
+ hooks.each do |proc_or_symbol|
115
+ unless proc_or_symbol.is_a?(Proc) || proc_or_symbol.is_a?(Symbol)
116
+ fail ArgumentError.new, 'Pass proc or symbol to on_error hook'
117
+ end
118
+ @rj_on_error_hooks << proc_or_symbol
119
+ end
121
120
  end
122
- end
123
121
 
124
- def queue(routing_key)
125
- raise ArgumentError.new("routing_key is nil") unless routing_key.present?
126
- @rj_queue = routing_key.to_sym
127
- end
128
-
129
- def perform_async(*args)
130
- RJ::Publisher.publish_to(@rj_queue || RJ.config.default_queue, self, *args)
131
- end
122
+ def queue(routing_key)
123
+ fail ArgumentError, 'routing_key is blank' if routing_key.blank?
124
+ @rj_queue = routing_key.to_sym
125
+ end
132
126
 
133
- def perform(*params)
134
- new.perform(*params)
135
- end
136
- end
127
+ def perform_async(*args)
128
+ RJ::Publisher.publish_to(@rj_queue, self, *args)
129
+ end
137
130
 
138
- def self.parse(payload)
139
- begin
140
- encoded = JSON.parse(payload)
141
- job_klass = encoded['class'].to_s.constantize
142
- job = job_klass.new(*encoded['params'])
143
- job.opts = encoded['opts']
144
- job
145
- rescue NameError
146
- [:not_found, encoded['class']]
147
- rescue JSON::ParserError
148
- [:parsing_error, payload]
149
- rescue
150
- [:error, $!, payload]
131
+ def perform(*params)
132
+ new.perform(*params)
133
+ end
151
134
  end
152
135
  end
153
-
154
- def self.serialize(klass_name, *params)
155
- {
156
- 'class' => klass_name.to_s,
157
- 'opts' => {'created_at' => Time.now.to_i},
158
- 'params' => params
159
- }.to_json
160
- end
161
136
  end
162
137
  end