dispatch-rider 1.5.3 → 1.6.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/lib/dispatch-rider.rb +1 -0
  4. data/lib/dispatch-rider/configuration.rb +12 -5
  5. data/lib/dispatch-rider/demultiplexer.rb +3 -27
  6. data/lib/dispatch-rider/logging.rb +10 -0
  7. data/lib/dispatch-rider/logging/base_formatter.rb +30 -0
  8. data/lib/dispatch-rider/logging/json_formatter.rb +75 -0
  9. data/lib/dispatch-rider/logging/lifecycle_logger.rb +53 -0
  10. data/lib/dispatch-rider/logging/text_formatter.rb +48 -0
  11. data/lib/dispatch-rider/queue_services/file_system/queue.rb +13 -2
  12. data/lib/dispatch-rider/version.rb +1 -1
  13. data/spec/lib/dispatch-rider/airbrake_error_handler_spec.rb +10 -3
  14. data/spec/lib/dispatch-rider/callbacks/access_spec.rb +16 -18
  15. data/spec/lib/dispatch-rider/callbacks/storage_spec.rb +4 -9
  16. data/spec/lib/dispatch-rider/configuration_spec.rb +3 -3
  17. data/spec/lib/dispatch-rider/default_error_handler_spec.rb +2 -2
  18. data/spec/lib/dispatch-rider/demultiplexer_spec.rb +14 -14
  19. data/spec/lib/dispatch-rider/dispatcher_spec.rb +10 -8
  20. data/spec/lib/dispatch-rider/handlers/base_spec.rb +27 -22
  21. data/spec/lib/dispatch-rider/handlers/inheritance_tracking_spec.rb +6 -6
  22. data/spec/lib/dispatch-rider/logging/json_formatter_spec.rb +72 -0
  23. data/spec/lib/dispatch-rider/logging/lifecycle_logger_spec.rb +73 -0
  24. data/spec/lib/dispatch-rider/logging/text_formatter_spec.rb +61 -0
  25. data/spec/lib/dispatch-rider/message_spec.rb +11 -11
  26. data/spec/lib/dispatch-rider/notification_services/aws_sns_spec.rb +14 -13
  27. data/spec/lib/dispatch-rider/notification_services/base_spec.rb +18 -13
  28. data/spec/lib/dispatch-rider/notification_services/file_system/channel_spec.rb +2 -3
  29. data/spec/lib/dispatch-rider/notification_services/file_system/notifier_spec.rb +1 -3
  30. data/spec/lib/dispatch-rider/notification_services/file_system_spec.rb +3 -4
  31. data/spec/lib/dispatch-rider/publisher/configuration/destination_spec.rb +30 -21
  32. data/spec/lib/dispatch-rider/publisher/configuration/notification_service_spec.rb +22 -16
  33. data/spec/lib/dispatch-rider/publisher/configuration_reader_spec.rb +11 -10
  34. data/spec/lib/dispatch-rider/publisher/configuration_spec.rb +12 -12
  35. data/spec/lib/dispatch-rider/publisher/configuration_support_spec.rb +11 -11
  36. data/spec/lib/dispatch-rider/publisher_spec.rb +22 -15
  37. data/spec/lib/dispatch-rider/queue_services/aws_sqs_spec.rb +44 -36
  38. data/spec/lib/dispatch-rider/queue_services/base_spec.rb +41 -28
  39. data/spec/lib/dispatch-rider/queue_services/file_system_spec.rb +15 -14
  40. data/spec/lib/dispatch-rider/queue_services/received_message_spec.rb +3 -3
  41. data/spec/lib/dispatch-rider/queue_services/simple_spec.rb +9 -9
  42. data/spec/lib/dispatch-rider/registrars/base_spec.rb +5 -5
  43. data/spec/lib/dispatch-rider/registrars/file_system_channel_spec.rb +3 -3
  44. data/spec/lib/dispatch-rider/registrars/handler_spec.rb +1 -1
  45. data/spec/lib/dispatch-rider/registrars/notification_service_spec.rb +1 -1
  46. data/spec/lib/dispatch-rider/registrars/publishing_destination_spec.rb +2 -2
  47. data/spec/lib/dispatch-rider/registrars/queue_service_spec.rb +1 -1
  48. data/spec/lib/dispatch-rider/registrars/sns_channel_spec.rb +5 -5
  49. data/spec/lib/dispatch-rider/runner_spec.rb +1 -1
  50. data/spec/lib/dispatch-rider/subscriber_spec.rb +45 -29
  51. data/spec/lib/dispatch-rider_spec.rb +3 -3
  52. data/spec/spec_helper.rb +3 -1
  53. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 00791dcc6642fcdce813e92abe1e6112af845b47
4
- data.tar.gz: 4db374187ef33441a01b17999c6c4dac5a87b535
3
+ metadata.gz: 865cf06c42c11dd3d75306800df557467d80a114
4
+ data.tar.gz: c86261b609d01cc2db299bf8cd5a74be20de1a95
5
5
  SHA512:
6
- metadata.gz: 89bd9117b23f3ae1a26c0e5b2bd0b5dafaf2509413ac5a06ed12f01b0acdbd29f61b9694a0a3805d92acc4b9c7dfa402b425a263f3fb91055d328d1f4778eb23
7
- data.tar.gz: 49054767ae3bc31d56144826a5d41d5b1410045b35020f264815e8e096cd7c9e7a6f2c55cffe446bd2743b8b082e0b37683cdd8dbe3acd3e4d527ea9bf929fb6
6
+ metadata.gz: ac475def2ee3a4fa688d4dd693da7da42e29f6826f880e9142532e5026533af96eec09d3d8bd79e735fbb09e7ce63d6a028a3a3c1bd8639e150d76e200ea5243
7
+ data.tar.gz: 28def6f13e59297cc5269443c94f22121fa87bae86d0fc6f02e436fe285ffb3d6605b245da91a56728b860c579238d7337d2a7beedc21aa60c7ffe536fc4e620
data/Gemfile CHANGED
@@ -14,8 +14,7 @@ gem 'github_changelog_generator'
14
14
  gem 'yard'
15
15
 
16
16
  # Testing
17
- gem "rspec", "~> 3.0"
18
- gem 'rspec-its'
17
+ gem "rspec", "~> 3.3"
19
18
 
20
19
  # CI
21
20
  gem "travis-lint"
@@ -23,3 +22,4 @@ gem "travis-lint"
23
22
  # Dev/Debugging
24
23
  gem "byebug", platform: :ruby_20, require: !ENV['CI']
25
24
  gem "aws-sdk", "~> 1"
25
+ gem "pry"
@@ -37,3 +37,4 @@ require "dispatch-rider/demultiplexer"
37
37
  require "dispatch-rider/runner"
38
38
  require "dispatch-rider/publisher"
39
39
  require "dispatch-rider/subscriber"
40
+ require "dispatch-rider/logging"
@@ -1,6 +1,6 @@
1
1
  module DispatchRider
2
2
  class Configuration
3
- attr_accessor :handler_path, :error_handler, :queue_info, :queue_kind, :subscriber, :logger, :debug
3
+ attr_accessor :handler_path, :error_handler, :queue_info, :queue_kind, :subscriber, :logger, :log_formatter, :debug
4
4
  attr_reader :callbacks
5
5
 
6
6
  def initialize
@@ -10,21 +10,28 @@ module DispatchRider
10
10
  @queue_info = { path: "tmp/dispatch-rider-queue" }
11
11
  @callbacks = Callbacks::Storage.new
12
12
  @subscriber = DispatchRider::Subscriber
13
+ @log_formatter = DispatchRider::Logging::TextFormatter.new
13
14
  @logger = Logger.new(STDERR)
14
15
  @debug = false
16
+
17
+ @callbacks.around(:handle_message) do |job, message|
18
+ Logging::LifecycleLogger.wrap_handling(message) do
19
+ job.call
20
+ end
21
+ end
15
22
  end
16
23
 
17
24
  delegate :before, :after, :around, :to => :callbacks
18
-
25
+
19
26
  def default_retry_timeout=(val)
20
27
  DispatchRider::Handlers::Base.set_default_retry(val)
21
28
  end
22
29
 
23
30
  def handlers
24
31
  @handlers ||= begin
25
- load_handler_files
26
- DispatchRider::Handlers::Base.subclasses.map{ |klass| klass.name.underscore.to_sym }
27
- end
32
+ load_handler_files
33
+ DispatchRider::Handlers::Base.subclasses.map { |klass| klass.name.underscore.to_sym }
34
+ end
28
35
  end
29
36
 
30
37
  private
@@ -29,9 +29,7 @@ module DispatchRider
29
29
 
30
30
  def stop(reason: nil)
31
31
  @continue = false
32
- if @current_message
33
- logger.info "Got stop #{reason ? '(' + reason + ') ' : ' ' }while executing: #{message_info_fragment(@current_message)}"
34
- end
32
+ Logging::LifecycleLogger.log_got_stop reason, @current_message if @current_message
35
33
  end
36
34
 
37
35
  private
@@ -64,39 +62,17 @@ module DispatchRider
64
62
  end
65
63
  end
66
64
 
67
- def message_info_fragment(message)
68
- "(#{message.guid}): #{message.subject} : #{message_info_arguments(message).inspect}"
69
- end
70
-
71
- def message_info_arguments(message)
72
- message.body.dup.tap { |m|
73
- m.delete('guid')
74
- }
75
- end
76
-
77
65
  def handle_next_queue_item
78
66
  queue.pop do |message|
79
- begin
80
- logger.info "Starting execution of: #{message_info_fragment(message)}"
81
- dispatch_message(message).tap {
82
- logger.info "Succeded execution of: #{message_info_fragment(message)}"
83
- }
84
- ensure
85
- logger.info "Completed execution of: #{message_info_fragment(message)}"
86
- end
67
+ dispatch_message(message)
87
68
  end
88
69
  end
89
70
 
90
- def exception_info_fragment(message, exception)
91
- "(#{message.object_id}): #{message.subject} with #{exception.class}: #{exception.message}"
92
- end
93
-
94
71
  def handle_message_error(message, exception)
95
72
  begin
96
- logger.error "Failed execution of: #{exception_info_fragment(message, exception)}"
97
73
  error_handler.call(message, exception)
98
74
  rescue => error_handler_exception # the error handler crashed
99
- logger.error "Failed error handling of: #{exception_info_fragment(message, error_handler_exception)}"
75
+ Logging::LifecycleLogger.log_error_handler_fail message, error_handler_exception
100
76
  raise error_handler_exception
101
77
  end
102
78
  end
@@ -0,0 +1,10 @@
1
+ module DispatchRider
2
+ module Logging
3
+
4
+ end
5
+ end
6
+
7
+ require_relative 'logging/lifecycle_logger'
8
+ require_relative 'logging/base_formatter'
9
+ require_relative 'logging/text_formatter'
10
+ require_relative 'logging/json_formatter'
@@ -0,0 +1,30 @@
1
+ module DispatchRider
2
+ module Logging
3
+ class BaseFormatter
4
+ def format_error_handler_fail(*)
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def format_got_stop(*)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def format_handling(*)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ private
17
+
18
+ def message_info_arguments(message)
19
+ message.body.dup.tap do |m|
20
+ m.delete('guid')
21
+ m.delete('object_id')
22
+ end
23
+ end
24
+
25
+ def format_duration(duration)
26
+ format '%.2f', duration
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,75 @@
1
+ require 'json'
2
+
3
+ # JSON Log Formatter
4
+ module DispatchRider
5
+ module Logging
6
+ class JsonFormatter < BaseFormatter
7
+ # @param [DispatchRider::QueueServices::ReceivedMessage] message
8
+ # @param [Exception] exception
9
+ # @return [String] JSON representation of the log item
10
+ def format_error_handler_fail(message, exception)
11
+ as_json do
12
+ {
13
+ phase: :failed,
14
+ }.merge exception_info_fragment(message, exception)
15
+ end
16
+ end
17
+
18
+ # @param [DispatchRider::QueueServices::ReceivedMessage] message
19
+ # @param [String] reason
20
+ # @return [String] JSON representation of the log item
21
+ def format_got_stop(message, reason)
22
+ as_json do
23
+ {
24
+ phase: :stop,
25
+ reason: reason,
26
+ }.merge message_info_fragment(message)
27
+ end
28
+ end
29
+
30
+ # @param [Symbol] kind of log action. one of: :start, :success, :fail, :complete
31
+ # @param [DispatchRider::QueueServices::ReceivedMessage] message
32
+ # @param [Exception] exception
33
+ # @param [Float] Job execution duration
34
+ # @return [String] JSON representation of the log item
35
+ def format_handling(kind, message, exception: nil, duration: nil)
36
+ as_json do
37
+ case kind
38
+ when :start
39
+ message_info_fragment(message)
40
+ when :success
41
+ message_info_fragment(message)
42
+ when :fail
43
+ exception_info_fragment(message, exception)
44
+ when :complete
45
+ { duration: format_duration(duration) }.merge message_info_fragment(message)
46
+ end.merge(phase: kind)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def as_json
53
+ JSON.generate yield
54
+ end
55
+
56
+ def message_info_fragment(message)
57
+ {
58
+ guid: message.guid.to_s,
59
+ subject: message.subject,
60
+ body: message_info_arguments(message),
61
+ }
62
+ end
63
+
64
+ def exception_info_fragment(message, exception)
65
+ exception_details = {
66
+ expection: {
67
+ class: exception.class.to_s,
68
+ message: exception.message,
69
+ }
70
+ }
71
+ message_info_fragment(message).merge exception_details
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,53 @@
1
+ module DispatchRider
2
+ module Logging
3
+ class LifecycleLogger
4
+ class << self
5
+ def log_error_handler_fail(message, exception)
6
+ logger.error formatter.format_error_handler_fail(message, exception)
7
+ end
8
+
9
+ def log_got_stop(reason, message)
10
+ logger.info formatter.format_got_stop(message, reason)
11
+ end
12
+
13
+ def wrap_handling(message)
14
+ log_start(message)
15
+ start_time = Time.now
16
+ yield
17
+ log_success(message)
18
+ rescue => exception
19
+ log_fail(message, exception)
20
+ raise exception
21
+ ensure
22
+ log_complete(message, Time.now - start_time)
23
+ end
24
+
25
+ private
26
+
27
+ def log_complete(message, duration)
28
+ logger.info formatter.format_handling :complete, message, duration: duration
29
+ end
30
+
31
+ def log_fail(message, exception)
32
+ logger.error formatter.format_handling :fail, message, exception: exception
33
+ end
34
+
35
+ def log_success(message)
36
+ logger.info formatter.format_handling :success, message
37
+ end
38
+
39
+ def log_start(message)
40
+ logger.info formatter.format_handling :start, message
41
+ end
42
+
43
+ def formatter
44
+ DispatchRider.config.log_formatter
45
+ end
46
+
47
+ def logger
48
+ DispatchRider.config.logger
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,48 @@
1
+ # Text Log Formatter
2
+ module DispatchRider
3
+ module Logging
4
+ class TextFormatter < BaseFormatter
5
+ # @param [DispatchRider::QueueServices::ReceivedMessage] message
6
+ # @param [Exception] exception
7
+ # @return [String] log item
8
+ def format_error_handler_fail(message, exception)
9
+ "Failed error handling of: #{exception_info_fragment(message, exception)}"
10
+ end
11
+
12
+ # @param [DispatchRider::QueueServices::ReceivedMessage] message
13
+ # @param [String] reason
14
+ # @return [String] log item
15
+ def format_got_stop(message, reason)
16
+ "Got stop #{reason ? '(' + reason + ') ' : ' ' }while executing: #{message_info_fragment(message)}"
17
+ end
18
+
19
+ # @param [Symbol] kind of log action. one of: :start, :success, :fail, :complete
20
+ # @param [DispatchRider::QueueServices::ReceivedMessage] message
21
+ # @param [Exception] exception
22
+ # @param [Float] Job execution duration
23
+ # @return [String] log item
24
+ def format_handling(kind, message, exception: nil, duration: nil)
25
+ case kind
26
+ when :start
27
+ "Starting execution of: #{message_info_fragment(message)}"
28
+ when :success
29
+ "Succeeded execution of: #{message_info_fragment(message)}"
30
+ when :fail
31
+ "Failed execution of: #{exception_info_fragment(message, exception)}"
32
+ when :complete
33
+ "Completed execution of: #{message_info_fragment(message)} in #{format_duration(duration)} seconds"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def message_info_fragment(message)
40
+ "(#{message.guid}): #{message.subject} : #{message_info_arguments(message).inspect}"
41
+ end
42
+
43
+ def exception_info_fragment(message, exception)
44
+ "(#{message.guid}): #{message.subject} with #{exception.class}: #{exception.message}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -15,13 +15,13 @@ module DispatchRider
15
15
  end
16
16
 
17
17
  def pop
18
- file_path = file_paths.first
18
+ file_path = next_item(10)
19
19
  return nil unless file_path
20
20
  file_path_inflight = file_path.gsub(/\.ready$/, '.inflight')
21
21
  FileUtils.mv(file_path, file_path_inflight)
22
22
  File.new(file_path_inflight)
23
23
  end
24
-
24
+
25
25
  def put_back(item)
26
26
  add(item)
27
27
  remove(item)
@@ -38,6 +38,17 @@ module DispatchRider
38
38
 
39
39
  private
40
40
 
41
+ # Long polling next item fetcher
42
+ # allows to sleep between checks for a new file and not run the main loop as much
43
+ def next_item(timeout = 10.seconds)
44
+ Timeout.timeout(timeout) do
45
+ sleep 1 until file_paths.first
46
+ file_paths.first
47
+ end
48
+ rescue Timeout::Error
49
+ nil
50
+ end
51
+
41
52
  def file_paths
42
53
  Dir["#{@path}/*.ready"]
43
54
  end
@@ -1,4 +1,4 @@
1
1
  # This file specifies the current version of the gem.
2
2
  module DispatchRider
3
- VERSION = "1.5.3"
3
+ VERSION = "1.6.0"
4
4
  end
@@ -3,11 +3,18 @@ require "spec_helper"
3
3
  describe DispatchRider::AirbrakeErrorHandler do
4
4
 
5
5
  describe ".call" do
6
- let(:message){ DispatchRider::Message.new(subject: "TestMessage", body: "foo" )}
7
- let(:exception){ Exception.new("Something went terribly wrong") }
6
+ let(:message) { DispatchRider::Message.new(subject: "TestMessage", body: "foo") }
7
+ let(:exception) { Exception.new("Something went terribly wrong") }
8
8
 
9
9
  example do
10
- Airbrake.should_receive(:notify).with(exception, controller: "DispatchRider", action: "TestMessage", parameters: { subject: "TestMessage", body: "foo" }, cgi_data: anything)
10
+ args = [
11
+ exception,
12
+ controller: "DispatchRider",
13
+ action: "TestMessage",
14
+ parameters: { subject: "TestMessage", body: "foo" },
15
+ cgi_data: anything,
16
+ ]
17
+ expect(Airbrake).to receive(:notify).with(*args)
11
18
 
12
19
  described_class.call(message, exception)
13
20
  end
@@ -2,7 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe DispatchRider::Callbacks::Access do
4
4
  describe "#invoke" do
5
-
6
5
  let(:callback_a1) { proc { |x| x.call } }
7
6
  let(:callback_a2) { proc { |x| x.call } }
8
7
  let(:callback_a3) { proc { |x| x.call } }
@@ -12,7 +11,7 @@ describe DispatchRider::Callbacks::Access do
12
11
  let(:callbacks_b) { [callback_b1] }
13
12
 
14
13
  let(:storage) { DispatchRider::Callbacks::Storage.new }
15
- let(:action) { proc { } }
14
+ let(:action) { proc {} }
16
15
 
17
16
  subject { described_class.new(storage) }
18
17
 
@@ -26,37 +25,36 @@ describe DispatchRider::Callbacks::Access do
26
25
  end
27
26
 
28
27
  example "a bunch of handlers" do
29
- callback_a1.should_receive(:call).once.and_call_original
30
- callback_a2.should_receive(:call).once.and_call_original
31
- callback_a3.should_receive(:call).once.and_call_original
32
- callback_b1.should_not_receive(:call)
28
+ expect(callback_a1).to receive(:call).once.and_call_original
29
+ expect(callback_a2).to receive(:call).once.and_call_original
30
+ expect(callback_a3).to receive(:call).once.and_call_original
31
+ expect(callback_b1).not_to receive(:call)
33
32
 
34
- action.should_receive(:call).once.and_call_original
33
+ expect(action).to receive(:call).once.and_call_original
35
34
 
36
35
  subject.invoke(:event1, &action)
37
36
  end
38
37
 
39
38
  example "single handler" do
40
- callback_a1.should_not_receive(:call)
41
- callback_a2.should_not_receive(:call)
42
- callback_a3.should_not_receive(:call)
43
- callback_b1.should_receive(:call).once.and_call_original
39
+ expect(callback_a1).not_to receive(:call)
40
+ expect(callback_a2).not_to receive(:call)
41
+ expect(callback_a3).not_to receive(:call)
42
+ expect(callback_b1).to receive(:call).once.and_call_original
44
43
 
45
- action.should_receive(:call).once.and_call_original
44
+ expect(action).to receive(:call).once.and_call_original
46
45
 
47
46
  subject.invoke(:event2, &action)
48
47
  end
49
48
 
50
49
  example "no handlers" do
51
- callback_a1.should_not_receive(:call)
52
- callback_a2.should_not_receive(:call)
53
- callback_a3.should_not_receive(:call)
54
- callback_b1.should_not_receive(:call)
50
+ expect(callback_a1).not_to receive(:call)
51
+ expect(callback_a2).not_to receive(:call)
52
+ expect(callback_a3).not_to receive(:call)
53
+ expect(callback_b1).not_to receive(:call)
55
54
 
56
- action.should_receive(:call).once.and_call_original
55
+ expect(action).to receive(:call).once.and_call_original
57
56
 
58
57
  subject.invoke(:event3, &action)
59
58
  end
60
59
  end
61
-
62
60
  end