eventboss 1.3.1 → 1.3.2
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 +4 -4
- data/.travis.yml +5 -0
- data/Gemfile.lock +6 -6
- data/README.md +42 -12
- data/lib/eventboss.rb +26 -11
- data/lib/eventboss/configuration.rb +33 -22
- data/lib/eventboss/development_mode.rb +48 -0
- data/lib/eventboss/error_handlers/logger.rb +1 -1
- data/lib/eventboss/launcher.rb +1 -1
- data/lib/eventboss/listener.rb +5 -8
- data/lib/eventboss/long_poller.rb +1 -1
- data/lib/eventboss/publisher.rb +7 -11
- data/lib/eventboss/queue.rb +36 -10
- data/lib/eventboss/queue_listener.rb +10 -14
- data/lib/eventboss/runner.rb +8 -3
- data/lib/eventboss/sns_client.rb +28 -5
- data/lib/eventboss/topic.rb +28 -0
- data/lib/eventboss/unit_of_work.rb +9 -8
- data/lib/eventboss/version.rb +1 -1
- data/lib/eventboss/worker.rb +4 -4
- metadata +5 -3
- data/.github/workflows/ruby.yml +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eaa1906368e8751476a4df0ae1f274a8008735de72191a34867881b50b19492b
|
4
|
+
data.tar.gz: 20bfe9695bc682e801b5b6760b92b9d575d0f323218b4286196aaff6f702d30f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1e03452ce05f49cd5cbc09875467145d41c9fe8e6239941f874394a9895c617a2a2843daa479833a498d8ccbed6e6ac64b85ca3dab8dc73f42e2f980ba99468
|
7
|
+
data.tar.gz: 6c8b23c2ace8d611e3a79f98dcf15a11a97dbba537a46ee97df970730ad0107eef117547697cdebbd2e4ab97404dd99dff388f6ccbfbccfcd9b5fdad9b68d5ae
|
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
eventboss (1.3.
|
4
|
+
eventboss (1.3.2)
|
5
5
|
aws-sdk-sns (>= 1.1.0)
|
6
6
|
aws-sdk-sqs (>= 1.3.0)
|
7
7
|
dotenv (~> 2.1, >= 2.1.1)
|
@@ -10,16 +10,16 @@ GEM
|
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
12
|
aws-eventstream (1.0.3)
|
13
|
-
aws-partitions (1.
|
14
|
-
aws-sdk-core (3.
|
13
|
+
aws-partitions (1.269.0)
|
14
|
+
aws-sdk-core (3.89.1)
|
15
15
|
aws-eventstream (~> 1.0, >= 1.0.2)
|
16
|
-
aws-partitions (~> 1, >= 1.
|
16
|
+
aws-partitions (~> 1, >= 1.239.0)
|
17
17
|
aws-sigv4 (~> 1.1)
|
18
18
|
jmespath (~> 1.0)
|
19
|
-
aws-sdk-sns (1.
|
19
|
+
aws-sdk-sns (1.21.0)
|
20
20
|
aws-sdk-core (~> 3, >= 3.71.0)
|
21
21
|
aws-sigv4 (~> 1.1)
|
22
|
-
aws-sdk-sqs (1.23.
|
22
|
+
aws-sdk-sqs (1.23.1)
|
23
23
|
aws-sdk-core (~> 3, >= 3.71.0)
|
24
24
|
aws-sigv4 (~> 1.1)
|
25
25
|
aws-sigv4 (1.1.0)
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Eventboss
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/eventboss)
|
4
|
+
[](https://travis-ci.org/AirHelp/eventboss)
|
4
5
|
|
5
6
|
AWS based Pub/Sub implementation in Ruby.
|
6
7
|
|
@@ -16,10 +17,10 @@ AWS based Pub/Sub implementation in Ruby.
|
|
16
17
|
* [x] support multiple environments in the same AWS account
|
17
18
|
* [x] pluggable error handlers (airbrake, newrelic)
|
18
19
|
* [x] utility tasks (deadletter reload)
|
19
|
-
* [x] localstack compatible
|
20
|
+
* [x] [localstack](https://github.com/localstack/localstack) compatible
|
20
21
|
* [x] rails support (preloads rails environment)
|
22
|
+
* [x] development mode (creates missing SNS/SQS on the fly)
|
21
23
|
* [ ] terraform pub/sub scripts
|
22
|
-
* [ ] development mode (creates missing SNS/SQS on the fly)
|
23
24
|
* [ ] alternative infrastructure (redis?, kafka?)
|
24
25
|
* [ ] message compression
|
25
26
|
* [ ] alternative serialization (protobuf)
|
@@ -93,15 +94,19 @@ end
|
|
93
94
|
Using ENVs:
|
94
95
|
|
95
96
|
```
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
EVENTBOSS_ACCOUNT_ID=12345676
|
98
|
+
EVENTBOSS_APP_NAME=application_name
|
99
|
+
EVENTBOSS_ENV=env_name # production/staging/test
|
100
|
+
EVENTBOSS_REGION=aws_region # i.e. eu-west-1
|
101
|
+
EVENTBOSS_CONCURRENCY=10 # default is 25
|
101
102
|
|
102
103
|
AWS_SNS_ENDPOINT=http://localhost:4575 # when using with localstack
|
103
104
|
AWS_SQS_ENDPOINT=http://localhost:4576 # when using with localstack
|
104
105
|
```
|
106
|
+
Use fixed account ID for localstack setup:
|
107
|
+
```
|
108
|
+
EVENTBUS_ACCOUNT_ID=000000000000
|
109
|
+
```
|
105
110
|
|
106
111
|
Be aware that `eventbus:deadletter:reload` rake task won't load your configuration if you are not using ENVs
|
107
112
|
in non Rails app, although to make it work you can extend your `Rakefile` with:
|
@@ -128,12 +133,12 @@ listeners:
|
|
128
133
|
exclude:
|
129
134
|
- OtherListener # When include option is not set it will run all listeners except listed here (OtherListener). When include is set it will run only included (but not excluded) listeners.
|
130
135
|
```
|
131
|
-
|
136
|
+
YAML config is optional and by default is loaded from `'./config/eventboss.yml'`.
|
132
137
|
You can also pass config path as an argument:
|
133
|
-
```
|
138
|
+
```sh
|
134
139
|
eventboss -C my/custom/path/to/config.yml
|
135
140
|
```
|
136
|
-
|
141
|
+
YAML config content is merged to configuration last, which means it overwrites ENVs and `.configure`.
|
137
142
|
|
138
143
|
### Logging and error handling
|
139
144
|
To have more verbose logging, set `log_level` in configuration (default is `info`).
|
@@ -146,9 +151,33 @@ Eventboss.configure do |config|
|
|
146
151
|
end
|
147
152
|
```
|
148
153
|
|
154
|
+
## Development mode
|
155
|
+
|
156
|
+
In the _development mode_ you don't need to create the infrastructure required by the application - Eventboss will take care of this.
|
157
|
+
|
158
|
+
It works on AWS and [localstack](https://github.com/localstack/localstack).
|
159
|
+
|
160
|
+
Following resources are created:
|
161
|
+
* SNS topics - created when application starts and when message is published
|
162
|
+
* SQS queues (with SendMessage policy) - created when application starts
|
163
|
+
* subscriptions for topics and queues - created when application starts
|
164
|
+
|
165
|
+
Just enable it via environment variable...
|
166
|
+
```
|
167
|
+
EVENTBUS_DEVELOPMENT_MODE=true
|
168
|
+
```
|
169
|
+
use fixed account ID for localstack setup...
|
170
|
+
```
|
171
|
+
EVENTBUS_ACCOUNT_ID=000000000000 # or set it via YAML
|
172
|
+
```
|
173
|
+
...and you're good to go:
|
174
|
+
```shell script
|
175
|
+
bundle exec eventboss
|
176
|
+
```
|
177
|
+
|
149
178
|
## Topics & Queues naming convention
|
150
179
|
|
151
|
-
The SNSes should be
|
180
|
+
The SNSes should be named in the following pattern:
|
152
181
|
```
|
153
182
|
eventboss-{src_app_name}-{event_name}-{environment}
|
154
183
|
```
|
@@ -158,7 +187,7 @@ i.e.
|
|
158
187
|
eventboss-srcapp-transaction_change-staging
|
159
188
|
```
|
160
189
|
|
161
|
-
The corresponding SQSes should be
|
190
|
+
The corresponding SQSes should be named like:
|
162
191
|
```
|
163
192
|
{dest_app_name}-eventboss-{src_app_name}-{event_name}-{environment}
|
164
193
|
{dest_app_name}-eventboss-{src_app_name}-{event_name}-{environment}-deadletter
|
@@ -177,3 +206,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/AirHel
|
|
177
206
|
## License
|
178
207
|
|
179
208
|
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
@@ -18,8 +18,10 @@ require 'eventboss/worker'
|
|
18
18
|
require 'eventboss/fetcher'
|
19
19
|
require 'eventboss/publisher'
|
20
20
|
require 'eventboss/sender'
|
21
|
+
require 'eventboss/topic'
|
21
22
|
require 'eventboss/runner'
|
22
23
|
require 'eventboss/extensions'
|
24
|
+
require 'eventboss/development_mode'
|
23
25
|
|
24
26
|
# For Rails use railtie, for plain Ruby apps use custom scripts loader
|
25
27
|
if defined?(Rails)
|
@@ -33,21 +35,34 @@ module Eventboss
|
|
33
35
|
|
34
36
|
class << self
|
35
37
|
def publisher(event_name, opts = {})
|
36
|
-
|
38
|
+
sns_client = configuration.sns_client
|
39
|
+
|
40
|
+
if configuration.development_mode?
|
41
|
+
source_app = configuration.eventboss_app_name unless opts[:generic]
|
42
|
+
topic_name = Topic.build_name(event_name: event_name, source_app: source_app)
|
43
|
+
sns_client.create_topic(name: topic_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
Publisher.new(event_name, sns_client, configuration, opts)
|
37
47
|
end
|
38
48
|
|
39
|
-
def sender(event_name,
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
49
|
+
def sender(event_name, destination, options = {})
|
50
|
+
source_app = configuration.eventboss_app_name unless options[:generic]
|
51
|
+
queue = Queue.build(
|
52
|
+
destination: destination,
|
53
|
+
source_app: source_app,
|
54
|
+
event_name: event_name,
|
55
|
+
env: env
|
46
56
|
)
|
57
|
+
sqs_client = configuration.sqs_client
|
58
|
+
|
59
|
+
if configuration.development_mode?
|
60
|
+
sqs_client.create_queue(queue_name: queue.name)
|
61
|
+
end
|
47
62
|
|
48
63
|
Sender.new(
|
49
|
-
client:
|
50
|
-
queue:
|
64
|
+
client: sqs_client,
|
65
|
+
queue: queue
|
51
66
|
)
|
52
67
|
end
|
53
68
|
|
@@ -56,7 +71,7 @@ module Eventboss
|
|
56
71
|
end
|
57
72
|
|
58
73
|
def env
|
59
|
-
@env ||= ENV['EVENTBUS_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV']
|
74
|
+
@env ||= ENV['EVENTBOSS_ENV'] || ENV['EVENTBUS_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV']
|
60
75
|
end
|
61
76
|
|
62
77
|
def configure
|
@@ -1,31 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Eventboss
|
2
4
|
class Configuration
|
3
5
|
OPTS_ALLOWED_IN_CONFIG_FILE = %i[
|
4
6
|
concurrency
|
5
7
|
sns_sqs_name_infix
|
6
8
|
listeners
|
7
|
-
]
|
9
|
+
].freeze
|
8
10
|
|
9
11
|
attr_writer :raise_on_missing_configuration,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
:error_handlers,
|
13
|
+
:concurrency,
|
14
|
+
:log_level,
|
15
|
+
:logger,
|
16
|
+
:sns_client,
|
17
|
+
:sqs_client,
|
18
|
+
:eventboss_region,
|
19
|
+
:eventboss_app_name,
|
20
|
+
:eventboss_account_id,
|
21
|
+
:aws_access_key_id,
|
22
|
+
:aws_secret_access_key,
|
23
|
+
:aws_sns_endpoint,
|
24
|
+
:aws_sqs_endpoint,
|
25
|
+
:sns_sqs_name_infix,
|
26
|
+
:listeners
|
25
27
|
|
26
28
|
|
27
29
|
def raise_on_missing_configuration
|
28
|
-
defined_or_default('raise_on_missing_configuration') { ENV['EVENTBUS_RAISE_ON_MISSING_CONFIGURATION']&.downcase == 'true' }
|
30
|
+
defined_or_default('raise_on_missing_configuration') { (ENV['EVENTBOSS_RAISE_ON_MISSING_CONFIGURATION'] || ENV['EVENTBUS_RAISE_ON_MISSING_CONFIGURATION'])&.downcase == 'true' }
|
29
31
|
end
|
30
32
|
|
31
33
|
def error_handlers
|
@@ -37,7 +39,10 @@ module Eventboss
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def concurrency
|
40
|
-
defined_or_default('concurrency')
|
42
|
+
defined_or_default('concurrency') do
|
43
|
+
concurrency = ENV['EVENTBOSS_CONCURRENCY'] || ENV['EVENTBUS_CONCURRENCY']
|
44
|
+
concurrency ? concurrency.to_i : 25
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
48
|
def log_level
|
@@ -72,15 +77,15 @@ module Eventboss
|
|
72
77
|
end
|
73
78
|
|
74
79
|
def eventboss_region
|
75
|
-
defined_or_default('eventboss_region') { ENV['EVENTBUS_REGION'] }
|
80
|
+
defined_or_default('eventboss_region') { ENV['EVENTBOSS_REGION'] || ENV['EVENTBUS_REGION'] }
|
76
81
|
end
|
77
82
|
|
78
83
|
def eventboss_app_name
|
79
|
-
defined_or_default('eventboss_app_name') { ENV['EVENTBUS_APP_NAME'] }
|
84
|
+
defined_or_default('eventboss_app_name') { ENV['EVENTBOSS_APP_NAME'] || ENV['EVENTBUS_APP_NAME'] }
|
80
85
|
end
|
81
86
|
|
82
87
|
def eventboss_account_id
|
83
|
-
defined_or_default('eventboss_account_id') { ENV['EVENTBUS_ACCOUNT_ID'] }
|
88
|
+
defined_or_default('eventboss_account_id') { ENV['EVENTBOSS_ACCOUNT_ID'] || ENV['EVENTBUS_ACCOUNT_ID'] }
|
84
89
|
end
|
85
90
|
|
86
91
|
def aws_access_key_id
|
@@ -100,13 +105,19 @@ module Eventboss
|
|
100
105
|
end
|
101
106
|
|
102
107
|
def sns_sqs_name_infix
|
103
|
-
defined_or_default('sns_sqs_name_infix') { ENV['EVENTBUS_SQS_SNS_NAME_INFIX'] || 'eventboss' }
|
108
|
+
defined_or_default('sns_sqs_name_infix') { ENV['EVENTBOSS_SQS_SNS_NAME_INFIX'] || ENV['EVENTBUS_SQS_SNS_NAME_INFIX'] || 'eventboss' }
|
104
109
|
end
|
105
110
|
|
106
111
|
def listeners
|
107
112
|
defined_or_default('listeners') { {} }
|
108
113
|
end
|
109
114
|
|
115
|
+
def development_mode?
|
116
|
+
defined_or_default('development_mode') do
|
117
|
+
(ENV['EVENTBOSS_DEVELOPMENT_MODE']&.downcase || ENV['EVENTBUS_DEVELOPMENT_MODE'])&.downcase == 'true'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
110
121
|
private
|
111
122
|
|
112
123
|
def defined_or_default(variable_name)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Eventboss
|
4
|
+
module DevelopmentMode
|
5
|
+
extend Logging
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def setup_infrastructure(queues)
|
9
|
+
sns_client = Eventboss.configuration.sns_client
|
10
|
+
sqs_client = Eventboss.configuration.sqs_client
|
11
|
+
|
12
|
+
queues.each do |queue, listener|
|
13
|
+
topic_name = Eventboss::Topic.build_name(**listener.options)
|
14
|
+
logger.info('development-mode') { "Creating topic #{topic_name}..." }
|
15
|
+
topic = sns_client.create_topic(name: topic_name)
|
16
|
+
|
17
|
+
logger.info('development-mode') { "Creating queue #{queue.name}..." }
|
18
|
+
sqs_client.create_queue(queue_name: queue.name)
|
19
|
+
|
20
|
+
logger.info('development-mode') { "Setting up queue #{queue.name} policy..." }
|
21
|
+
policy = queue_policy(queue.arn, topic.topic_arn)
|
22
|
+
sqs_client.set_queue_attributes(queue_url: queue.url, attributes: { Policy: policy.to_json })
|
23
|
+
|
24
|
+
logger.info('development-mode') { "Creating subscription for topic #{topic.topic_arn} and #{queue.arn}..." }
|
25
|
+
sns_client.create_subscription(topic_arn: topic.topic_arn, queue_arn: queue.arn)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def queue_policy(queue_arn, topic_arn)
|
30
|
+
{
|
31
|
+
"Version": "2012-10-17",
|
32
|
+
"Statement": [{
|
33
|
+
"Sid": "queue-policy-#{queue_arn}-#{topic_arn}",
|
34
|
+
"Effect": "Allow",
|
35
|
+
"Principal": "*",
|
36
|
+
"Action": ["SQS:SendMessage"],
|
37
|
+
"Resource": "#{queue_arn}",
|
38
|
+
"Condition": {
|
39
|
+
"ArnEquals": {
|
40
|
+
"aws:SourceArn": "#{topic_arn}"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}]
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -6,7 +6,7 @@ module Eventboss
|
|
6
6
|
notice[:jid] = notice[:processor].jid if notice[:processor]
|
7
7
|
notice[:processor] = notice[:processor].class.to_s if notice[:processor]
|
8
8
|
Eventboss.logger.error(notice) do
|
9
|
-
"Failure processing request #{exception.message}"
|
9
|
+
"Failure processing request: #{exception.message}"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
data/lib/eventboss/launcher.rb
CHANGED
data/lib/eventboss/listener.rb
CHANGED
@@ -17,15 +17,12 @@ module Eventboss
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module ClassMethods
|
20
|
-
|
21
|
-
source_app = opts[:source_app] ? "#{opts[:source_app]}-" : ""
|
22
|
-
event_name = opts[:event_name]
|
23
|
-
destination_app = opts[:destination_app]
|
20
|
+
attr_reader :options
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
def eventboss_options(options)
|
23
|
+
@options = options.compact
|
24
|
+
|
25
|
+
ACTIVE_LISTENERS[@options] = self
|
29
26
|
end
|
30
27
|
end
|
31
28
|
end
|
@@ -44,7 +44,7 @@ module Eventboss
|
|
44
44
|
def fetch_and_dispatch
|
45
45
|
fetch_messages.each do |message|
|
46
46
|
logger.debug(id) { "enqueueing message #{message.message_id}" }
|
47
|
-
@bus << UnitOfWork.new(queue, listener, message)
|
47
|
+
@bus << UnitOfWork.new(@client, queue, listener, message)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
data/lib/eventboss/publisher.rb
CHANGED
@@ -1,32 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Eventboss
|
2
4
|
class Publisher
|
3
5
|
def initialize(event_name, sns_client, configuration, opts = {})
|
4
6
|
@event_name = event_name
|
5
7
|
@sns_client = sns_client
|
6
8
|
@configuration = configuration
|
7
|
-
@
|
9
|
+
@source = configuration.eventboss_app_name unless opts[:generic]
|
8
10
|
end
|
9
11
|
|
10
12
|
def publish(payload)
|
11
|
-
|
13
|
+
topic_arn = Topic.build_arn(event_name: event_name, source_app: source)
|
14
|
+
sns_client.publish(
|
12
15
|
topic_arn: topic_arn,
|
13
16
|
message: json_payload(payload)
|
14
|
-
|
17
|
+
)
|
15
18
|
end
|
16
19
|
|
17
20
|
private
|
18
21
|
|
19
|
-
attr_reader :event_name, :sns_client, :configuration
|
22
|
+
attr_reader :event_name, :sns_client, :configuration, :source
|
20
23
|
|
21
24
|
def json_payload(payload)
|
22
25
|
payload.is_a?(String) ? payload : payload.to_json
|
23
26
|
end
|
24
|
-
|
25
|
-
def topic_arn
|
26
|
-
src_selector = @generic ? "" : "-#{configuration.eventboss_app_name}"
|
27
|
-
|
28
|
-
"arn:aws:sns:#{configuration.eventboss_region}:#{configuration.eventboss_account_id}:\
|
29
|
-
#{Eventboss.configuration.sns_sqs_name_infix}#{src_selector}-#{event_name}-#{Eventboss.env}"
|
30
|
-
end
|
31
27
|
end
|
32
28
|
end
|
data/lib/eventboss/queue.rb
CHANGED
@@ -1,21 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Eventboss
|
2
4
|
class Queue
|
3
5
|
include Comparable
|
4
6
|
attr_reader :name
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
class << self
|
9
|
+
def build_name(destination:, event_name:, env:, source_app: nil)
|
10
|
+
[
|
11
|
+
destination,
|
12
|
+
Eventboss.configuration.sns_sqs_name_infix,
|
13
|
+
source_app,
|
14
|
+
event_name,
|
15
|
+
env
|
16
|
+
].compact.join('-')
|
17
|
+
end
|
13
18
|
|
14
|
-
|
19
|
+
def build(destination:, event_name:, env:, source_app: nil)
|
20
|
+
name = build_name(
|
21
|
+
destination: destination,
|
22
|
+
event_name: event_name,
|
23
|
+
env: env,
|
24
|
+
source_app: source_app
|
25
|
+
)
|
26
|
+
Queue.new(name)
|
27
|
+
end
|
15
28
|
end
|
16
29
|
|
17
|
-
def initialize(name
|
18
|
-
@client = configuration.sqs_client
|
30
|
+
def initialize(name)
|
31
|
+
@client = Eventboss.configuration.sqs_client
|
19
32
|
@name = name
|
20
33
|
end
|
21
34
|
|
@@ -23,6 +36,15 @@ module Eventboss
|
|
23
36
|
@url ||= client.get_queue_url(queue_name: name).queue_url
|
24
37
|
end
|
25
38
|
|
39
|
+
def arn
|
40
|
+
[
|
41
|
+
'arn:aws:sqs',
|
42
|
+
Eventboss.configuration.eventboss_region,
|
43
|
+
Eventboss.configuration.eventboss_account_id,
|
44
|
+
name
|
45
|
+
].join(':')
|
46
|
+
end
|
47
|
+
|
26
48
|
def <=>(another_queue)
|
27
49
|
name <=> another_queue&.name
|
28
50
|
end
|
@@ -35,6 +57,10 @@ module Eventboss
|
|
35
57
|
name.hash
|
36
58
|
end
|
37
59
|
|
60
|
+
def to_s
|
61
|
+
"<Eventboss::Queue: #{name}>"
|
62
|
+
end
|
63
|
+
|
38
64
|
private
|
39
65
|
|
40
66
|
attr_reader :client
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Eventboss
|
2
2
|
class QueueListener
|
3
3
|
class << self
|
4
|
-
def select(include
|
4
|
+
def select(include: nil, exclude: nil)
|
5
5
|
listeners = list.values.map(&:name)
|
6
6
|
|
7
7
|
listeners &= include if include
|
@@ -13,19 +13,15 @@ module Eventboss
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def list
|
16
|
-
|
17
|
-
|
18
|
-
Eventboss
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
),
|
26
|
-
opts[:listener]
|
27
|
-
]
|
28
|
-
end]
|
16
|
+
Eventboss::Listener::ACTIVE_LISTENERS.each_with_object({}) do |(eventboss_options, listener), queue_listeners|
|
17
|
+
queue = Eventboss::Queue.build(
|
18
|
+
destination: eventboss_options[:destination_app] || Eventboss.configuration.eventboss_app_name,
|
19
|
+
source_app: eventboss_options[:source_app],
|
20
|
+
event_name: eventboss_options[:event_name],
|
21
|
+
env: Eventboss.env
|
22
|
+
)
|
23
|
+
queue_listeners[queue] = listener
|
24
|
+
end
|
29
25
|
end
|
30
26
|
end
|
31
27
|
end
|
data/lib/eventboss/runner.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Eventboss
|
2
4
|
class Runner
|
3
5
|
extend Logging
|
@@ -17,8 +19,11 @@ module Eventboss
|
|
17
19
|
|
18
20
|
self_read = setup_signals([:SIGTERM])
|
19
21
|
|
20
|
-
logger.info('Active
|
21
|
-
logger.info(
|
22
|
+
logger.info('Active listeners:')
|
23
|
+
queues.each { |queue, listener| logger.info("#{queue}: #{listener}") }
|
24
|
+
|
25
|
+
Eventboss::DevelopmentMode.setup_infrastructure(queues) if config.development_mode?
|
26
|
+
|
22
27
|
begin
|
23
28
|
launcher.start
|
24
29
|
handle_signals(self_read, launcher)
|
@@ -45,7 +50,7 @@ module Eventboss
|
|
45
50
|
def handle_signals(self_read, launcher)
|
46
51
|
while readable_io = IO.select([self_read])
|
47
52
|
signal = readable_io.first[0].gets.strip
|
48
|
-
logger.info('runner') { "Received #{
|
53
|
+
logger.info('runner') { "Received #{signal} signal, gracefully shutting down..." }
|
49
54
|
|
50
55
|
launcher.stop
|
51
56
|
exit 0
|
data/lib/eventboss/sns_client.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Eventboss
|
2
|
-
class NotConfigured < StandardError;
|
4
|
+
class NotConfigured < StandardError;
|
5
|
+
end
|
3
6
|
|
4
7
|
class SnsClient
|
5
8
|
def initialize(configuration)
|
@@ -10,10 +13,31 @@ module Eventboss
|
|
10
13
|
backend.publish(payload)
|
11
14
|
end
|
12
15
|
|
16
|
+
def create_topic(name:)
|
17
|
+
backend.create_topic(name: name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_subscription(topic_arn:, queue_arn:)
|
21
|
+
subscription = backend.subscribe(
|
22
|
+
topic_arn: topic_arn,
|
23
|
+
endpoint: queue_arn,
|
24
|
+
protocol: 'sqs'
|
25
|
+
)
|
26
|
+
set_raw_message_delivery(subscription)
|
27
|
+
end
|
28
|
+
|
13
29
|
private
|
14
30
|
|
15
31
|
attr_reader :configuration
|
16
32
|
|
33
|
+
def set_raw_message_delivery(subscription)
|
34
|
+
backend.set_subscription_attributes(
|
35
|
+
subscription_arn: subscription.subscription_arn,
|
36
|
+
attribute_name: 'RawMessageDelivery',
|
37
|
+
attribute_value: 'true'
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
17
41
|
def backend
|
18
42
|
if configured?
|
19
43
|
options = {
|
@@ -26,11 +50,10 @@ module Eventboss
|
|
26
50
|
if configuration.aws_sns_endpoint
|
27
51
|
options[:endpoint] = configuration.aws_sns_endpoint
|
28
52
|
end
|
29
|
-
|
30
|
-
|
31
|
-
)
|
53
|
+
|
54
|
+
Aws::SNS::Client.new(options)
|
32
55
|
elsif configuration.raise_on_missing_configuration
|
33
|
-
raise NotConfigured, 'Eventboss is not configured'
|
56
|
+
raise NotConfigured, 'Eventboss is not configured.'
|
34
57
|
else
|
35
58
|
Mock.new
|
36
59
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Eventboss
|
4
|
+
class Topic
|
5
|
+
class << self
|
6
|
+
def build_arn(event_name:, source_app: nil)
|
7
|
+
[
|
8
|
+
'arn:aws:sns',
|
9
|
+
Eventboss.configuration.eventboss_region,
|
10
|
+
Eventboss.configuration.eventboss_account_id,
|
11
|
+
build_name(
|
12
|
+
event_name: event_name,
|
13
|
+
source_app: source_app
|
14
|
+
)
|
15
|
+
].join(':')
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_name(event_name:, source_app: nil)
|
19
|
+
[
|
20
|
+
Eventboss.configuration.sns_sqs_name_infix,
|
21
|
+
source_app,
|
22
|
+
event_name,
|
23
|
+
Eventboss.env
|
24
|
+
].compact.join('-')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -6,14 +6,15 @@ module Eventboss
|
|
6
6
|
|
7
7
|
attr_accessor :queue, :listener, :message
|
8
8
|
|
9
|
-
def initialize(queue, listener, message)
|
9
|
+
def initialize(client, queue, listener, message)
|
10
|
+
@client = client
|
10
11
|
@queue = queue
|
11
12
|
@listener = listener
|
12
13
|
@message = message
|
13
14
|
@logger = logger
|
14
15
|
end
|
15
16
|
|
16
|
-
def run
|
17
|
+
def run
|
17
18
|
logger.debug(@message.message_id) { 'Started' }
|
18
19
|
processor = @listener.new
|
19
20
|
processor.receive(JSON.parse(@message.body))
|
@@ -21,21 +22,21 @@ module Eventboss
|
|
21
22
|
rescue StandardError => exception
|
22
23
|
handle_exception(exception, processor: processor, message_id: @message.message_id)
|
23
24
|
else
|
24
|
-
cleanup
|
25
|
+
cleanup unless processor.postponed_by
|
25
26
|
ensure
|
26
|
-
change_message_visibility(
|
27
|
+
change_message_visibility(processor.postponed_by) if processor.postponed_by
|
27
28
|
end
|
28
29
|
|
29
|
-
def change_message_visibility(
|
30
|
-
client.change_message_visibility(
|
30
|
+
def change_message_visibility(postponed_by)
|
31
|
+
@client.change_message_visibility(
|
31
32
|
queue_url: @queue.url,
|
32
33
|
receipt_handle: @message.receipt_handle,
|
33
34
|
visibility_timeout: postponed_by
|
34
35
|
)
|
35
36
|
end
|
36
37
|
|
37
|
-
def cleanup
|
38
|
-
client.delete_message(
|
38
|
+
def cleanup
|
39
|
+
@client.delete_message(
|
39
40
|
queue_url: @queue.url, receipt_handle: @message.receipt_handle
|
40
41
|
)
|
41
42
|
logger.debug(@message.message_id) { 'Deleting' }
|
data/lib/eventboss/version.rb
CHANGED
data/lib/eventboss/worker.rb
CHANGED
@@ -6,12 +6,12 @@ module Eventboss
|
|
6
6
|
|
7
7
|
attr_reader :id
|
8
8
|
|
9
|
-
def initialize(launcher, id,
|
9
|
+
def initialize(launcher, id, bus, restart_on: [Exception])
|
10
10
|
@id = "worker-#{id}"
|
11
11
|
@launcher = launcher
|
12
|
-
@client = client
|
13
12
|
@bus = bus
|
14
13
|
@thread = nil
|
14
|
+
@restart_on = restart_on
|
15
15
|
end
|
16
16
|
|
17
17
|
def start
|
@@ -20,12 +20,12 @@ module Eventboss
|
|
20
20
|
|
21
21
|
def run
|
22
22
|
while (work = @bus.pop)
|
23
|
-
work.run
|
23
|
+
work.run
|
24
24
|
end
|
25
25
|
@launcher.worker_stopped(self)
|
26
26
|
rescue Eventboss::Shutdown
|
27
27
|
@launcher.worker_stopped(self)
|
28
|
-
rescue
|
28
|
+
rescue *@restart_on => exception
|
29
29
|
handle_exception(exception, worker_id: id)
|
30
30
|
# Restart the worker in case of hard exception
|
31
31
|
# Message won't be delete from SQS and will be visible later
|
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.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AirHelp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-sqs
|
@@ -108,9 +108,9 @@ executables:
|
|
108
108
|
extensions: []
|
109
109
|
extra_rdoc_files: []
|
110
110
|
files:
|
111
|
-
- ".github/workflows/ruby.yml"
|
112
111
|
- ".gitignore"
|
113
112
|
- ".rspec"
|
113
|
+
- ".travis.yml"
|
114
114
|
- CHANGELOG.md
|
115
115
|
- Gemfile
|
116
116
|
- Gemfile.lock
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- lib/eventboss.rb
|
124
124
|
- lib/eventboss/cli.rb
|
125
125
|
- lib/eventboss/configuration.rb
|
126
|
+
- lib/eventboss/development_mode.rb
|
126
127
|
- lib/eventboss/error_handlers/airbrake.rb
|
127
128
|
- lib/eventboss/error_handlers/db_connection_drop_handler.rb
|
128
129
|
- lib/eventboss/error_handlers/logger.rb
|
@@ -142,6 +143,7 @@ files:
|
|
142
143
|
- lib/eventboss/scripts.rb
|
143
144
|
- lib/eventboss/sender.rb
|
144
145
|
- lib/eventboss/sns_client.rb
|
146
|
+
- lib/eventboss/topic.rb
|
145
147
|
- lib/eventboss/unit_of_work.rb
|
146
148
|
- lib/eventboss/version.rb
|
147
149
|
- lib/eventboss/worker.rb
|
data/.github/workflows/ruby.yml
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
name: Ruby
|
2
|
-
|
3
|
-
on: [push]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
build:
|
7
|
-
|
8
|
-
runs-on: ubuntu-latest
|
9
|
-
|
10
|
-
steps:
|
11
|
-
- uses: actions/checkout@v1
|
12
|
-
- name: Set up Ruby 2.6
|
13
|
-
uses: actions/setup-ruby@v1
|
14
|
-
with:
|
15
|
-
ruby-version: 2.6.x
|
16
|
-
- name: Build and test with Rake
|
17
|
-
run: |
|
18
|
-
gem install bundler
|
19
|
-
bundle install --jobs 4 --retry 3
|
20
|
-
bundle exec rake
|