eventboss 1.3.3 → 1.7.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
  SHA256:
3
- metadata.gz: 75049f48f1c8433cfa188e43b2b01aa1362460f14e54cf86147dddea8f37b554
4
- data.tar.gz: 22828a987f1b8d6e3eaa3b1c6944a515e379729ab19190c99c232277d0f71463
3
+ metadata.gz: 8b837d9db4a587bec35fc7d31765551263011c2bd33559944c7de34ffa885c3b
4
+ data.tar.gz: 3b0f1808873bf4a8d2b5407b82de0ced2f86a2bd5f67775f4f3c73493dfe1bd7
5
5
  SHA512:
6
- metadata.gz: 9f11ff92660d9eb27d1d5d6b0fb7c778887c5fccf7e133d6f0d27679d751aa078c93e7e5b0f90fc259a0c86a2a17e82480ffb985ec0ecead9c2fedb0779f5fa1
7
- data.tar.gz: e2b5673cfce08d06ffef4ef74ab742765e45b03905ebaad2cbd32495c0b0b28ec3b4c7620c0180c8e0e9662b9992ea115a4621397040f98dbd3535d852978db8
6
+ metadata.gz: d7c7a8696654ccefd5d25596a9f439c8fbbd8ca41a71525f195010fbb0f469db5f6937632e0b6c46a67cb774b67fc3aeec174e507e649f46c2ab76e55ea56dee
7
+ data.tar.gz: 4d7c2b81fc401f5d7890ad1144ee87cd933a34470110a50b7d94e6d88fbcf5792f938777f7b93b3ec37280dc09d5b7c17f2e2b9ac9dc34f50f0c8ed4075af8ed
data/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.4.0] - 2020-04-18
8
+
9
+ - Introduce server middlewares (#31)
10
+
7
11
  ## [1.1.0] - 2019-07-16
8
12
 
9
13
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- eventboss (1.3.3)
4
+ eventboss (1.7.0)
5
5
  aws-sdk-sns (>= 1.1.0)
6
6
  aws-sdk-sqs (>= 1.3.0)
7
7
  dotenv (~> 2.1, >= 2.1.1)
@@ -9,23 +9,23 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- aws-eventstream (1.0.3)
13
- aws-partitions (1.281.0)
14
- aws-sdk-core (3.90.1)
15
- aws-eventstream (~> 1.0, >= 1.0.2)
12
+ aws-eventstream (1.1.1)
13
+ aws-partitions (1.432.0)
14
+ aws-sdk-core (3.113.0)
15
+ aws-eventstream (~> 1, >= 1.0.2)
16
16
  aws-partitions (~> 1, >= 1.239.0)
17
17
  aws-sigv4 (~> 1.1)
18
18
  jmespath (~> 1.0)
19
- aws-sdk-sns (1.21.0)
20
- aws-sdk-core (~> 3, >= 3.71.0)
19
+ aws-sdk-sns (1.37.0)
20
+ aws-sdk-core (~> 3, >= 3.109.0)
21
21
  aws-sigv4 (~> 1.1)
22
- aws-sdk-sqs (1.23.1)
23
- aws-sdk-core (~> 3, >= 3.71.0)
22
+ aws-sdk-sqs (1.35.0)
23
+ aws-sdk-core (~> 3, >= 3.109.0)
24
24
  aws-sigv4 (~> 1.1)
25
- aws-sigv4 (1.1.1)
26
- aws-eventstream (~> 1.0, >= 1.0.2)
25
+ aws-sigv4 (1.2.3)
26
+ aws-eventstream (~> 1, >= 1.0.2)
27
27
  diff-lcs (1.3)
28
- dotenv (2.7.5)
28
+ dotenv (2.7.6)
29
29
  jmespath (1.4.0)
30
30
  rake (13.0.1)
31
31
  rspec (3.7.0)
@@ -52,4 +52,4 @@ DEPENDENCIES
52
52
  rspec (~> 3.0)
53
53
 
54
54
  BUNDLED WITH
55
- 1.17.3
55
+ 2.1.4
data/README.md CHANGED
@@ -151,20 +151,52 @@ Eventboss.configure do |config|
151
151
  end
152
152
  ```
153
153
 
154
- ## Development mode
154
+ ### Middlewares
155
+
156
+ Server middlewares intercept the execution of your `Listeners`. You can use to extract and run common functions on every message received.
157
+
158
+ Define a middleware in the following way:
159
+
160
+ ```ruby
161
+ class LogMiddleware < Eventboss::Middleware::Base
162
+ def call(_work)
163
+ yield
164
+ logger.debug 'finished with success'
165
+ rescue StandardError => _error
166
+ logger.error 'finished with error'
167
+ raise
168
+ end
169
+
170
+ private
171
+
172
+ def logger
173
+ @logger ||= @options.fetch(:logger)
174
+ end
175
+ end
176
+ ```
177
+
178
+ And configure your logger as such:
179
+
180
+ ```ruby
181
+ Eventboss.configure do |config|
182
+ config.server_middleware.add LogMiddleware, logger: Logger.new
183
+ end
184
+ ```
185
+
186
+ ## Development mode
155
187
 
156
188
  In the _development mode_ you don't need to create the infrastructure required by the application - Eventboss will take care of this.
157
189
 
158
190
  It works on AWS and [localstack](https://github.com/localstack/localstack).
159
191
 
160
- Following resources are created:
192
+ Following resources are created:
161
193
  * SNS topics - created when application starts and when message is published
162
194
  * SQS queues (with SendMessage policy) - created when application starts
163
195
  * subscriptions for topics and queues - created when application starts
164
196
 
165
197
  Just enable it via environment variable...
166
198
  ```
167
- EVENTBUS_DEVELOPMENT_MODE=true
199
+ EVENTBOSS_DEVELOPMENT_MODE=true
168
200
  ```
169
201
  use fixed account ID for localstack setup...
170
202
  ```
@@ -206,4 +238,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/AirHel
206
238
  ## License
207
239
 
208
240
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
209
-
data/lib/eventboss.rb CHANGED
@@ -13,6 +13,7 @@ require 'eventboss/logging'
13
13
  require 'eventboss/safe_thread'
14
14
  require 'eventboss/launcher'
15
15
  require 'eventboss/long_poller'
16
+ require 'eventboss/middleware'
16
17
  require 'eventboss/unit_of_work'
17
18
  require 'eventboss/worker'
18
19
  require 'eventboss/fetcher'
@@ -25,15 +25,15 @@ module Eventboss
25
25
  :sns_sqs_name_infix,
26
26
  :listeners
27
27
 
28
-
29
28
  def raise_on_missing_configuration
30
29
  defined_or_default('raise_on_missing_configuration') { (ENV['EVENTBOSS_RAISE_ON_MISSING_CONFIGURATION'] || ENV['EVENTBUS_RAISE_ON_MISSING_CONFIGURATION'])&.downcase == 'true' }
31
30
  end
32
31
 
33
32
  def error_handlers
34
33
  defined_or_default('error_handlers') do
35
- [ErrorHandlers::Logger.new].tap do |handlers|
34
+ [ErrorHandlers::Logger.new, ErrorHandlers::NonExistentQueueHandler.new].tap do |handlers|
36
35
  handlers << ErrorHandlers::DbConnectionDropHandler.new if defined?(::ActiveRecord::StatementInvalid)
36
+ handlers << ErrorHandlers::DbConnectionNotEstablishedHandler.new if defined?(::ActiveRecord::ConnectionNotEstablished)
37
37
  end
38
38
  end
39
39
  end
@@ -118,6 +118,10 @@ module Eventboss
118
118
  end
119
119
  end
120
120
 
121
+ def server_middleware
122
+ @server_middleware ||= Middleware::Chain.new
123
+ end
124
+
121
125
  private
122
126
 
123
127
  def defined_or_default(variable_name)
@@ -0,0 +1,11 @@
1
+ module Eventboss
2
+ module ErrorHandlers
3
+ class DbConnectionNotEstablishedHandler
4
+ def call(exception, _context = {})
5
+ if exception.class == ::ActiveRecord::ConnectionNotEstablished
6
+ ::ActiveRecord::Base.connection.reconnect!
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module Eventboss
2
+ module ErrorHandlers
3
+ class NonExistentQueueHandler
4
+ def call(exception, context = {})
5
+ if exception.class == ::Aws::SQS::Errors::NonExistentQueue
6
+ queue = context.fetch(:poller_id, "").sub('poller-', '')
7
+ Eventboss.logger.error("Queue doesn't exist: " + queue)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Eventboss
2
+ module ErrorHandlers
3
+ class Rollbar
4
+ def call(exception, context = {})
5
+ eventboss_context = { component: 'eventboss' }
6
+ eventboss_context[:action] = context[:processor].class.to_s if context[:processor]
7
+ ::Rollbar.error(exception, eventboss_context.merge(context))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,6 @@
1
1
  require 'eventboss/error_handlers/logger'
2
2
  require 'eventboss/error_handlers/airbrake'
3
+ require 'eventboss/error_handlers/rollbar'
3
4
  require 'eventboss/error_handlers/db_connection_drop_handler'
5
+ require 'eventboss/error_handlers/db_connection_not_established_handler'
6
+ require 'eventboss/error_handlers/non_existent_queue_handler'
@@ -34,6 +34,7 @@ module Eventboss
34
34
  @bus.clear
35
35
  @pollers.each(&:terminate)
36
36
  @workers.each(&:terminate)
37
+ @bus.close
37
38
 
38
39
  wait_for_shutdown
39
40
  hard_shutdown
@@ -70,7 +71,7 @@ module Eventboss
70
71
  end
71
72
 
72
73
  def new_worker(id)
73
- Worker.new(self, id, @bus)
74
+ Worker.new(self, "worker-#{id}", @bus)
74
75
  end
75
76
 
76
77
  def new_poller(queue, listener)
@@ -45,6 +45,8 @@ module Eventboss
45
45
  fetch_messages.each do |message|
46
46
  logger.debug(id) { "enqueueing message #{message.message_id}" }
47
47
  @bus << UnitOfWork.new(@client, queue, listener, message)
48
+ rescue ClosedQueueError
49
+ logger.info(id) { "skip message #{message.message_id} enqueuing due to closed queue" }
48
50
  end
49
51
  end
50
52
 
@@ -53,6 +55,9 @@ module Eventboss
53
55
  @launcher.poller_stopped(self)
54
56
  rescue Eventboss::Shutdown
55
57
  @launcher.poller_stopped(self)
58
+ rescue Aws::SQS::Errors::NonExistentQueue
59
+ handle_exception(exception, poller_id: id)
60
+ @launcher.poller_stopped(self)
56
61
  rescue StandardError => exception
57
62
  handle_exception(exception, poller_id: id)
58
63
  # Give a chance for temporary AWS errors to be resolved
@@ -0,0 +1,57 @@
1
+ module Eventboss
2
+ module Middleware
3
+ class Chain
4
+ attr_reader :entries
5
+
6
+ def initialize
7
+ @entries = []
8
+ end
9
+
10
+ def add(klass, options = {})
11
+ @entries << Entry.new(klass, options)
12
+ end
13
+
14
+ def invoke(*args)
15
+ chain = @entries.map(&:build).reverse!
16
+
17
+ invoke_lambda = lambda do
18
+ if (mid = chain.pop)
19
+ mid.call(*args, &invoke_lambda)
20
+ else
21
+ yield
22
+ end
23
+ end
24
+ invoke_lambda.call
25
+ end
26
+
27
+ def clear
28
+ @entries.clear
29
+ end
30
+ end
31
+
32
+ class Base
33
+ attr_reader :options
34
+
35
+ def initialize(options)
36
+ @options = options
37
+ end
38
+
39
+ def call
40
+ raise 'Not implemented'
41
+ end
42
+ end
43
+
44
+ class Entry
45
+ attr_reader :klass, :options
46
+
47
+ def initialize(klass, options)
48
+ @klass = klass
49
+ @options = options
50
+ end
51
+
52
+ def build
53
+ @klass.new(options)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,3 +1,3 @@
1
1
  module Eventboss
2
- VERSION = "1.3.3"
2
+ VERSION = "1.7.0"
3
3
  end
@@ -7,7 +7,7 @@ module Eventboss
7
7
  attr_reader :id
8
8
 
9
9
  def initialize(launcher, id, bus, restart_on: [Exception])
10
- @id = "worker-#{id}"
10
+ @id = id
11
11
  @launcher = launcher
12
12
  @bus = bus
13
13
  @thread = nil
@@ -20,7 +20,7 @@ module Eventboss
20
20
 
21
21
  def run
22
22
  while (work = @bus.pop)
23
- work.run
23
+ run_work(work)
24
24
  end
25
25
  @launcher.worker_stopped(self)
26
26
  rescue Eventboss::Shutdown
@@ -32,6 +32,12 @@ module Eventboss
32
32
  @launcher.worker_stopped(self, restart: true)
33
33
  end
34
34
 
35
+ def run_work(work)
36
+ server_middleware.invoke(work) do
37
+ work.run
38
+ end
39
+ end
40
+
35
41
  def terminate(wait = false)
36
42
  stop_token
37
43
  return unless @thread
@@ -39,7 +45,6 @@ module Eventboss
39
45
  end
40
46
 
41
47
  def kill(wait = false)
42
- stop_token
43
48
  return unless @thread
44
49
  @thread.raise Eventboss::Shutdown
45
50
  @thread.value if wait
@@ -51,5 +56,9 @@ module Eventboss
51
56
  def stop_token
52
57
  @bus << nil
53
58
  end
59
+
60
+ def server_middleware
61
+ Eventboss.configuration.server_middleware
62
+ end
54
63
  end
55
64
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= event_name.camelize %>Listener
4
+ include Eventboss::Listener
5
+
6
+ eventboss_options event_name: '<%= event_name %>'<%= source_app ? ", source_app: '#{ source_app }'" : "" %>
7
+
8
+ def receive(payload)
9
+ Rails.logger.tagged(jid) { Rails.logger.info("payload: #{ payload }") }
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Creates the Eventboss listener scaffold
4
+ #
5
+ # @example Invocation from terminal
6
+ # rails generate eventboss:listener get_well air-helper
7
+ #
8
+ module Eventboss
9
+ class ListenerGenerator < Rails::Generators::Base
10
+ source_root File.expand_path(__dir__)
11
+
12
+ argument :event_name, required: true
13
+ argument :source_app, required: false
14
+
15
+ desc 'Creates the Eventboss listener scaffold'
16
+ def create_listener_scaffold
17
+ template 'eventboss_listener.rb.erb', "app/listeners/#{ event_name }_listener.rb"
18
+ end
19
+ end
20
+ end
@@ -33,7 +33,6 @@ namespace :eventboss do
33
33
  break if messages.count.zero?
34
34
 
35
35
  messages.each do |message|
36
- puts "[#{task.name}] Publishing message: #{message.body}"
37
36
  client.send_message(queue_url: send_queue.url, message_body: message.body)
38
37
  fetcher.delete(queue, message)
39
38
 
@@ -71,7 +70,6 @@ namespace :eventboss do
71
70
  break if messages.count.zero?
72
71
 
73
72
  messages.each do |message|
74
- puts "[#{task.name}] Deleting message: #{message.body}"
75
73
  fetcher.delete(queue, message)
76
74
 
77
75
  total += 1
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventboss
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - AirHelp
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-09 00:00:00.000000000 Z
11
+ date: 2021-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-sqs
@@ -126,7 +126,10 @@ files:
126
126
  - lib/eventboss/development_mode.rb
127
127
  - lib/eventboss/error_handlers/airbrake.rb
128
128
  - lib/eventboss/error_handlers/db_connection_drop_handler.rb
129
+ - lib/eventboss/error_handlers/db_connection_not_established_handler.rb
129
130
  - lib/eventboss/error_handlers/logger.rb
131
+ - lib/eventboss/error_handlers/non_existent_queue_handler.rb
132
+ - lib/eventboss/error_handlers/rollbar.rb
130
133
  - lib/eventboss/extensions.rb
131
134
  - lib/eventboss/fetcher.rb
132
135
  - lib/eventboss/instrumentation.rb
@@ -134,6 +137,7 @@ files:
134
137
  - lib/eventboss/listener.rb
135
138
  - lib/eventboss/logging.rb
136
139
  - lib/eventboss/long_poller.rb
140
+ - lib/eventboss/middleware.rb
137
141
  - lib/eventboss/publisher.rb
138
142
  - lib/eventboss/queue.rb
139
143
  - lib/eventboss/queue_listener.rb
@@ -147,12 +151,14 @@ files:
147
151
  - lib/eventboss/unit_of_work.rb
148
152
  - lib/eventboss/version.rb
149
153
  - lib/eventboss/worker.rb
154
+ - lib/generators/eventboss/listener/eventboss_listener.rb.erb
155
+ - lib/generators/eventboss/listener/listener_generator.rb
150
156
  - lib/tasks/eventboss.rake
151
157
  homepage: https://github.com/AirHelp/eventboss
152
158
  licenses:
153
159
  - MIT
154
160
  metadata: {}
155
- post_install_message:
161
+ post_install_message:
156
162
  rdoc_options: []
157
163
  require_paths:
158
164
  - lib
@@ -167,8 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
173
  - !ruby/object:Gem::Version
168
174
  version: '0'
169
175
  requirements: []
170
- rubygems_version: 3.0.3
171
- signing_key:
176
+ rubygems_version: 3.1.6
177
+ signing_key:
172
178
  specification_version: 4
173
179
  summary: Eventboss Ruby Client.
174
180
  test_files: []