eventboss 1.3.3 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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: []