hutch-java 1.3.0-java

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 (81) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +57 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +899 -0
  7. data/Gemfile +35 -0
  8. data/Guardfile +14 -0
  9. data/LICENSE +23 -0
  10. data/README.md +679 -0
  11. data/Rakefile +21 -0
  12. data/bin/ci/before_build.sh +20 -0
  13. data/bin/ci/before_build_docker.sh +20 -0
  14. data/bin/ci/install_on_debian.sh +46 -0
  15. data/bin/hutch +8 -0
  16. data/examples/consumer.rb +13 -0
  17. data/examples/producer.rb +10 -0
  18. data/hutch.gemspec +27 -0
  19. data/lib/hutch/acknowledgements/base.rb +16 -0
  20. data/lib/hutch/acknowledgements/nack_on_all_failures.rb +19 -0
  21. data/lib/hutch/adapter.rb +11 -0
  22. data/lib/hutch/adapters/bunny.rb +37 -0
  23. data/lib/hutch/adapters/march_hare.rb +41 -0
  24. data/lib/hutch/broker.rb +383 -0
  25. data/lib/hutch/cli.rb +246 -0
  26. data/lib/hutch/config.rb +304 -0
  27. data/lib/hutch/consumer.rb +125 -0
  28. data/lib/hutch/error_handlers/airbrake.rb +54 -0
  29. data/lib/hutch/error_handlers/base.rb +15 -0
  30. data/lib/hutch/error_handlers/bugsnag.rb +30 -0
  31. data/lib/hutch/error_handlers/honeybadger.rb +43 -0
  32. data/lib/hutch/error_handlers/logger.rb +22 -0
  33. data/lib/hutch/error_handlers/rollbar.rb +28 -0
  34. data/lib/hutch/error_handlers/sentry.rb +26 -0
  35. data/lib/hutch/error_handlers/sentry_raven.rb +31 -0
  36. data/lib/hutch/error_handlers.rb +11 -0
  37. data/lib/hutch/exceptions.rb +14 -0
  38. data/lib/hutch/logging.rb +32 -0
  39. data/lib/hutch/message.rb +31 -0
  40. data/lib/hutch/publisher.rb +75 -0
  41. data/lib/hutch/serializers/identity.rb +19 -0
  42. data/lib/hutch/serializers/json.rb +22 -0
  43. data/lib/hutch/tracers/datadog.rb +18 -0
  44. data/lib/hutch/tracers/newrelic.rb +19 -0
  45. data/lib/hutch/tracers/null_tracer.rb +15 -0
  46. data/lib/hutch/tracers.rb +7 -0
  47. data/lib/hutch/version.rb +3 -0
  48. data/lib/hutch/waiter.rb +104 -0
  49. data/lib/hutch/worker.rb +145 -0
  50. data/lib/hutch.rb +69 -0
  51. data/lib/yard-settings/handler.rb +38 -0
  52. data/lib/yard-settings/yard-settings.rb +2 -0
  53. data/spec/hutch/broker_spec.rb +462 -0
  54. data/spec/hutch/cli_spec.rb +93 -0
  55. data/spec/hutch/config_spec.rb +259 -0
  56. data/spec/hutch/consumer_spec.rb +208 -0
  57. data/spec/hutch/error_handlers/airbrake_spec.rb +49 -0
  58. data/spec/hutch/error_handlers/bugsnag_spec.rb +55 -0
  59. data/spec/hutch/error_handlers/honeybadger_spec.rb +58 -0
  60. data/spec/hutch/error_handlers/logger_spec.rb +28 -0
  61. data/spec/hutch/error_handlers/rollbar_spec.rb +45 -0
  62. data/spec/hutch/error_handlers/sentry_raven_spec.rb +37 -0
  63. data/spec/hutch/error_handlers/sentry_spec.rb +47 -0
  64. data/spec/hutch/logger_spec.rb +34 -0
  65. data/spec/hutch/message_spec.rb +38 -0
  66. data/spec/hutch/serializers/json_spec.rb +17 -0
  67. data/spec/hutch/tracers/datadog_spec.rb +44 -0
  68. data/spec/hutch/waiter_spec.rb +51 -0
  69. data/spec/hutch/worker_spec.rb +184 -0
  70. data/spec/hutch_spec.rb +87 -0
  71. data/spec/spec_helper.rb +42 -0
  72. data/templates/default/class/html/settings.erb +0 -0
  73. data/templates/default/class/setup.rb +4 -0
  74. data/templates/default/fulldoc/html/css/hutch.css +13 -0
  75. data/templates/default/layout/html/setup.rb +7 -0
  76. data/templates/default/method_details/html/settings.erb +5 -0
  77. data/templates/default/method_details/setup.rb +4 -0
  78. data/templates/default/method_details/text/settings.erb +0 -0
  79. data/templates/default/module/html/settings.erb +40 -0
  80. data/templates/default/module/setup.rb +4 -0
  81. metadata +204 -0
@@ -0,0 +1,145 @@
1
+ require 'hutch/message'
2
+ require 'hutch/logging'
3
+ require 'hutch/broker'
4
+ require 'hutch/acknowledgements/nack_on_all_failures'
5
+ require 'hutch/waiter'
6
+ require 'carrot-top'
7
+ require 'securerandom'
8
+
9
+ module Hutch
10
+ class Worker
11
+ include Logging
12
+
13
+ def initialize(broker, consumers, setup_procs)
14
+ @broker = broker
15
+ self.consumers = consumers
16
+ self.setup_procs = setup_procs
17
+ end
18
+
19
+ # Run the main event loop. The consumers will be set up with queues, and
20
+ # process the messages in their respective queues indefinitely. This method
21
+ # never returns.
22
+ def run
23
+ setup_queues
24
+ setup_procs.each(&:call)
25
+
26
+ Waiter.wait_until_signaled
27
+
28
+ stop
29
+ end
30
+
31
+ # Stop a running worker by killing all subscriber threads.
32
+ def stop
33
+ @broker.stop
34
+ end
35
+
36
+ # Set up the queues for each of the worker's consumers.
37
+ def setup_queues
38
+ logger.info 'setting up queues'
39
+ vetted = @consumers.reject { |c| group_configured? && group_restricted?(c) }
40
+ vetted.each do |c|
41
+ setup_queue(c)
42
+ end
43
+ end
44
+
45
+ # Bind a consumer's routing keys to its queue, and set up a subscription to
46
+ # receive messages sent to the queue.
47
+ def setup_queue(consumer)
48
+ logger.info "setting up queue: #{consumer.get_queue_name}"
49
+
50
+ queue = @broker.queue(consumer.get_queue_name, consumer.get_options)
51
+ @broker.bind_queue(queue, consumer.routing_keys)
52
+
53
+ queue.subscribe(consumer_tag: unique_consumer_tag, manual_ack: true) do |*args|
54
+ delivery_info, properties, payload = Hutch::Adapter.decode_message(*args)
55
+ handle_message(consumer, delivery_info, properties, payload)
56
+ end
57
+ end
58
+
59
+ # Called internally when a new messages comes in from RabbitMQ. Responsible
60
+ # for wrapping up the message and passing it to the consumer.
61
+ def handle_message(consumer, delivery_info, properties, payload)
62
+ serializer = consumer.get_serializer || Hutch::Config[:serializer]
63
+ logger.debug {
64
+ spec = serializer.binary? ? "#{payload.bytesize} bytes" : "#{payload}"
65
+ "message(#{properties.message_id || '-'}): " +
66
+ "routing key: #{delivery_info.routing_key}, " +
67
+ "consumer: #{consumer}, " +
68
+ "payload: #{spec}"
69
+ }
70
+
71
+ message = Message.new(delivery_info, properties, payload, serializer)
72
+ consumer_instance = consumer.new.tap { |c| c.broker, c.delivery_info = @broker, delivery_info }
73
+ with_tracing(consumer_instance).handle(message)
74
+ @broker.ack(delivery_info.delivery_tag) unless consumer_instance.message_rejected?
75
+ rescue => ex
76
+ acknowledge_error(delivery_info, properties, @broker, ex)
77
+ handle_error(properties, payload, consumer, ex)
78
+ end
79
+
80
+ def with_tracing(klass)
81
+ Hutch::Config[:tracer].new(klass)
82
+ end
83
+
84
+ def handle_error(*args)
85
+ Hutch::Config[:error_handlers].each do |backend|
86
+ backend.handle(*args)
87
+ end
88
+ end
89
+
90
+ def acknowledge_error(delivery_info, properties, broker, ex)
91
+ acks = error_acknowledgements +
92
+ [Hutch::Acknowledgements::NackOnAllFailures.new]
93
+ acks.find do |backend|
94
+ backend.handle(delivery_info, properties, broker, ex)
95
+ end
96
+ end
97
+
98
+ def consumers=(val)
99
+ if val.empty?
100
+ logger.warn "no consumer loaded, ensure there's no configuration issue"
101
+ end
102
+ @consumers = val
103
+ end
104
+
105
+ def error_acknowledgements
106
+ Hutch::Config[:error_acknowledgements]
107
+ end
108
+
109
+ private
110
+
111
+ def group_configured?
112
+ if group.present? && consumer_groups.blank?
113
+ logger.info 'Consumer groups are blank'
114
+ end
115
+ group.present?
116
+ end
117
+
118
+ def group_restricted?(consumer)
119
+ consumers_to_load = consumer_groups[group]
120
+ if consumers_to_load
121
+ !consumers_to_load.include?(consumer.name)
122
+ else
123
+ true
124
+ end
125
+ end
126
+
127
+ def group
128
+ Hutch::Config[:group]
129
+ end
130
+
131
+ def consumer_groups
132
+ Hutch::Config[:consumer_groups]
133
+ end
134
+
135
+ attr_accessor :setup_procs
136
+
137
+ def unique_consumer_tag
138
+ prefix = Hutch::Config[:consumer_tag_prefix]
139
+ unique_part = SecureRandom.uuid
140
+ "#{prefix}-#{unique_part}".tap do |tag|
141
+ raise "Tag must be 255 bytes long at most, current one is #{tag.bytesize} ('#{tag}')" if tag.bytesize > 255
142
+ end
143
+ end
144
+ end
145
+ end
data/lib/hutch.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'hutch/adapter'
2
+ require 'hutch/consumer'
3
+ require 'hutch/worker'
4
+ require 'hutch/broker'
5
+ require 'hutch/logging'
6
+ require 'hutch/serializers/identity'
7
+ require 'hutch/serializers/json'
8
+ require 'hutch/config'
9
+ require 'hutch/message'
10
+ require 'hutch/cli'
11
+ require 'hutch/version'
12
+ require 'hutch/error_handlers'
13
+ require 'hutch/exceptions'
14
+ require 'hutch/tracers'
15
+
16
+ module Hutch
17
+ @@connection_mutex = Mutex.new
18
+
19
+ def self.register_consumer(consumer)
20
+ self.consumers << consumer
21
+ end
22
+
23
+ def self.consumers
24
+ @consumers ||= []
25
+ end
26
+
27
+ def self.logger
28
+ Hutch::Logging.logger
29
+ end
30
+
31
+ def self.global_properties=(properties)
32
+ @global_properties = properties
33
+ end
34
+
35
+ def self.global_properties
36
+ @global_properties ||= {}
37
+ end
38
+
39
+ # Connects to broker, if not yet connected.
40
+ #
41
+ # @param options [Hash] Connection options
42
+ # @param config [Hash] Configuration
43
+ # @option options [Boolean] :enable_http_api_use
44
+ def self.connect(options = {}, config = Hutch::Config)
45
+ @@connection_mutex.synchronize do
46
+ unless connected?
47
+ @broker = Hutch::Broker.new(config)
48
+ @broker.connect(options)
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.disconnect
54
+ @broker.disconnect if @broker
55
+ end
56
+
57
+ def self.broker
58
+ @broker
59
+ end
60
+
61
+ # @return [Boolean]
62
+ def self.connected?
63
+ broker && broker.connection && broker.connection.open?
64
+ end
65
+
66
+ def self.publish(*args)
67
+ broker.publish(*args)
68
+ end
69
+ end
@@ -0,0 +1,38 @@
1
+ # :nodoc:
2
+ class SettingsHandlerBase < YARD::Handlers::Ruby::Base
3
+ handles method_call :string_setting
4
+ handles method_call :number_setting
5
+ handles method_call :boolean_setting
6
+
7
+ namespace_only
8
+
9
+ def process
10
+ name = statement.parameters.first.jump(:tstring_content, :ident).source
11
+ object = YARD::CodeObjects::MethodObject.new(namespace, name)
12
+ register(object)
13
+
14
+ # Modify the code object for the new instance method
15
+ object.dynamic = true
16
+ # Add custom metadata to the object
17
+ object['custom_field'] = '(Found using method_missing)'
18
+
19
+ # Module-level configuration notes
20
+ hutch_config = YARD::CodeObjects::ModuleObject.new(:root, "Hutch::Config")
21
+ collection_name = statement.first.first
22
+ default_value = statement.parameters[1].jump(:tstring_content, :ident).source
23
+
24
+ (hutch_config['setting_rows'] ||= []) << {
25
+ name: name,
26
+ default_value: default_value,
27
+ type: collection_name.sub('_setting', '').capitalize,
28
+ description: object.docstring,
29
+ first_line_of_description: first_line_of_description(object)
30
+ }
31
+ end
32
+
33
+ def first_line_of_description(object)
34
+ return '' if object.docstring.blank?
35
+
36
+ object.docstring.lines.first
37
+ end
38
+ end
@@ -0,0 +1,2 @@
1
+ YARD::Templates::Engine.register_template_path(File.dirname(__FILE__) + '/../../templates')
2
+ require File.join(File.dirname(__FILE__), 'handler') if RUBY19