pwwka 0.23.RC1 → 1.0.0.RC1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +161 -30
- data/.ruby-version +1 -1
- data/CODEOWNERS +1 -0
- data/Gemfile.rails-6.1 +7 -0
- data/Gemfile.rails-7.0 +7 -0
- data/README.md +19 -8
- data/lib/pwwka/configuration.rb +7 -3
- data/lib/pwwka/logging.rb +4 -1
- data/lib/pwwka/transmitter.rb +38 -12
- data/lib/pwwka/version.rb +1 -1
- data/lib/pwwka.rb +0 -1
- data/owners.json +1 -1
- data/pwwka.gemspec +2 -2
- data/spec/integration/send_and_receive_spec.rb +26 -5
- data/spec/spec_helper.rb +7 -2
- data/spec/unit/configuration_spec.rb +9 -1
- data/spec/unit/logging_spec.rb +38 -0
- data/spec/unit/transmitter_spec.rb +44 -8
- metadata +15 -20
- data/Gemfile.rails-4.2 +0 -8
- data/Gemfile.rails-5.0 +0 -8
- data/Gemfile.rails-5.1 +0 -8
- data/Gemfile.rails-5.2 +0 -8
- data/lib/pwwka/persistent_transmitter.rb +0 -59
- data/spec/unit/persistent_transmitter_spec.rb +0 -153
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbe20aa33393b941e9a8dfc21eff7c787ca7c1beb7daa8fa81a1e7846717ede9
|
4
|
+
data.tar.gz: edaa4a73e2a920241ebb3ffd9598fca93a1fd8c3b975dc11c2035cc059e90905
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 669be067f88ac9a7138134cdde10d8ca2888319633d108317f61bf4ea64fb5fc85de2a731273fa88281c85b8444d2ee2033a8513e8ee0926a18eb0b8eb6201af
|
7
|
+
data.tar.gz: 87775761df6856f4396e0f1900d794dcf91bfb4a264395cd900f7e485324796644ae7d4223daa87c3120b1f0ebf990abdce32b3a2f80e9213bd5cd93a4cb6a26
|
data/.circleci/config.yml
CHANGED
@@ -1,19 +1,72 @@
|
|
1
|
-
# DO NOT MODIFY - this is managed by Git Reduce in goro
|
1
|
+
# DO NOT MODIFY - this is managed by Git Reduce in goro and generated from build-matrix.json
|
2
2
|
#
|
3
3
|
---
|
4
4
|
version: 2
|
5
5
|
jobs:
|
6
|
-
|
6
|
+
generate-and-push-docs:
|
7
7
|
docker:
|
8
|
-
- image:
|
8
|
+
- image: cimg/ruby:3.0.3
|
9
|
+
auth:
|
10
|
+
username: "$DOCKERHUB_USERNAME"
|
11
|
+
password: "$DOCKERHUB_PASSWORD"
|
12
|
+
steps:
|
13
|
+
- checkout
|
14
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
15
|
+
- run: bundle install
|
16
|
+
- run:
|
17
|
+
name: Generate documentation
|
18
|
+
command: ' if [[ $(bundle exec rake -T docs:generate:custom) ]]; then echo
|
19
|
+
"Generating docs using rake task docs:generate:custom" ; bundle exec rake
|
20
|
+
docs:generate:custom ; elif [[ $(bundle exec rake -T docs:generate) ]];
|
21
|
+
then echo "Generating docs using rake task docs:generate" ; bundle exec
|
22
|
+
rake docs:generate ; else echo "Skipping doc generation" ; exit 0 ; fi '
|
23
|
+
- run:
|
24
|
+
name: Push documentation to Unwritten
|
25
|
+
command: if [[ $(bundle exec rake -T docs:push) ]]; then bundle exec rake
|
26
|
+
docs:push; fi
|
27
|
+
release:
|
28
|
+
docker:
|
29
|
+
- image: cimg/ruby:3.0.3
|
30
|
+
auth:
|
31
|
+
username: "$DOCKERHUB_USERNAME"
|
32
|
+
password: "$DOCKERHUB_PASSWORD"
|
33
|
+
steps:
|
34
|
+
- checkout
|
35
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
36
|
+
- run: bundle install
|
37
|
+
- run:
|
38
|
+
name: Artifactory login
|
39
|
+
command: mkdir -p ~/.gem && curl -u$ARTIFACTORY_USER:$ARTIFACTORY_TOKEN https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/api/v1/api_key.yaml
|
40
|
+
> ~/.gem/credentials && chmod 0600 ~/.gem/credentials
|
41
|
+
- run:
|
42
|
+
name: Build/release gem to artifactory
|
43
|
+
command: bundle exec rake push_artifactory
|
44
|
+
ruby-3.0.3-rails-7.0:
|
45
|
+
docker:
|
46
|
+
- image: cimg/ruby:3.0.3
|
47
|
+
auth:
|
48
|
+
username: "$DOCKERHUB_USERNAME"
|
49
|
+
password: "$DOCKERHUB_PASSWORD"
|
9
50
|
environment:
|
10
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
51
|
+
BUNDLE_GEMFILE: Gemfile.rails-7.0
|
11
52
|
- image: redis:2.8.12
|
53
|
+
auth:
|
54
|
+
username: "$DOCKERHUB_USERNAME"
|
55
|
+
password: "$DOCKERHUB_PASSWORD"
|
12
56
|
- image: rabbitmq:3.5.6
|
57
|
+
auth:
|
58
|
+
username: "$DOCKERHUB_USERNAME"
|
59
|
+
password: "$DOCKERHUB_PASSWORD"
|
13
60
|
working_directory: "~/pwwka"
|
14
61
|
steps:
|
15
62
|
- checkout
|
16
|
-
- run:
|
63
|
+
- run:
|
64
|
+
name: Check for Gemfile.lock presence
|
65
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
66
|
+
https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
67
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
68
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
69
|
+
- run: bundle install
|
17
70
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
18
71
|
--format=doc
|
19
72
|
- run:
|
@@ -22,21 +75,36 @@ jobs:
|
|
22
75
|
fi
|
23
76
|
- run:
|
24
77
|
name: Notify Pager Duty
|
25
|
-
command:
|
78
|
+
command: bundle exec y-notify "#eng-messaging-ops"
|
26
79
|
when: on_fail
|
27
80
|
- store_test_results:
|
28
81
|
path: "/tmp/test-results"
|
29
|
-
ruby-2.5
|
82
|
+
ruby-2.7.5-rails-7.0:
|
30
83
|
docker:
|
31
|
-
- image:
|
84
|
+
- image: cimg/ruby:2.7.5
|
85
|
+
auth:
|
86
|
+
username: "$DOCKERHUB_USERNAME"
|
87
|
+
password: "$DOCKERHUB_PASSWORD"
|
32
88
|
environment:
|
33
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
89
|
+
BUNDLE_GEMFILE: Gemfile.rails-7.0
|
34
90
|
- image: redis:2.8.12
|
91
|
+
auth:
|
92
|
+
username: "$DOCKERHUB_USERNAME"
|
93
|
+
password: "$DOCKERHUB_PASSWORD"
|
35
94
|
- image: rabbitmq:3.5.6
|
95
|
+
auth:
|
96
|
+
username: "$DOCKERHUB_USERNAME"
|
97
|
+
password: "$DOCKERHUB_PASSWORD"
|
36
98
|
working_directory: "~/pwwka"
|
37
99
|
steps:
|
38
100
|
- checkout
|
39
|
-
- run:
|
101
|
+
- run:
|
102
|
+
name: Check for Gemfile.lock presence
|
103
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
104
|
+
https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
105
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
106
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
107
|
+
- run: bundle install
|
40
108
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
41
109
|
--format=doc
|
42
110
|
- run:
|
@@ -45,21 +113,36 @@ jobs:
|
|
45
113
|
fi
|
46
114
|
- run:
|
47
115
|
name: Notify Pager Duty
|
48
|
-
command:
|
116
|
+
command: bundle exec y-notify "#eng-messaging-ops"
|
49
117
|
when: on_fail
|
50
118
|
- store_test_results:
|
51
119
|
path: "/tmp/test-results"
|
52
|
-
ruby-
|
120
|
+
ruby-3.0.3-rails-6.1:
|
53
121
|
docker:
|
54
|
-
- image:
|
122
|
+
- image: cimg/ruby:3.0.3
|
123
|
+
auth:
|
124
|
+
username: "$DOCKERHUB_USERNAME"
|
125
|
+
password: "$DOCKERHUB_PASSWORD"
|
55
126
|
environment:
|
56
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
127
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.1
|
57
128
|
- image: redis:2.8.12
|
129
|
+
auth:
|
130
|
+
username: "$DOCKERHUB_USERNAME"
|
131
|
+
password: "$DOCKERHUB_PASSWORD"
|
58
132
|
- image: rabbitmq:3.5.6
|
133
|
+
auth:
|
134
|
+
username: "$DOCKERHUB_USERNAME"
|
135
|
+
password: "$DOCKERHUB_PASSWORD"
|
59
136
|
working_directory: "~/pwwka"
|
60
137
|
steps:
|
61
138
|
- checkout
|
62
|
-
- run:
|
139
|
+
- run:
|
140
|
+
name: Check for Gemfile.lock presence
|
141
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
142
|
+
https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
143
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
144
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
145
|
+
- run: bundle install
|
63
146
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
64
147
|
--format=doc
|
65
148
|
- run:
|
@@ -68,21 +151,36 @@ jobs:
|
|
68
151
|
fi
|
69
152
|
- run:
|
70
153
|
name: Notify Pager Duty
|
71
|
-
command:
|
154
|
+
command: bundle exec y-notify "#eng-messaging-ops"
|
72
155
|
when: on_fail
|
73
156
|
- store_test_results:
|
74
157
|
path: "/tmp/test-results"
|
75
|
-
ruby-2.5
|
158
|
+
ruby-2.7.5-rails-6.1:
|
76
159
|
docker:
|
77
|
-
- image:
|
160
|
+
- image: cimg/ruby:2.7.5
|
161
|
+
auth:
|
162
|
+
username: "$DOCKERHUB_USERNAME"
|
163
|
+
password: "$DOCKERHUB_PASSWORD"
|
78
164
|
environment:
|
79
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
165
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.1
|
80
166
|
- image: redis:2.8.12
|
167
|
+
auth:
|
168
|
+
username: "$DOCKERHUB_USERNAME"
|
169
|
+
password: "$DOCKERHUB_PASSWORD"
|
81
170
|
- image: rabbitmq:3.5.6
|
171
|
+
auth:
|
172
|
+
username: "$DOCKERHUB_USERNAME"
|
173
|
+
password: "$DOCKERHUB_PASSWORD"
|
82
174
|
working_directory: "~/pwwka"
|
83
175
|
steps:
|
84
176
|
- checkout
|
85
|
-
- run:
|
177
|
+
- run:
|
178
|
+
name: Check for Gemfile.lock presence
|
179
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
180
|
+
https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
181
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
182
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
183
|
+
- run: bundle install
|
86
184
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
87
185
|
--format=doc
|
88
186
|
- run:
|
@@ -91,7 +189,7 @@ jobs:
|
|
91
189
|
fi
|
92
190
|
- run:
|
93
191
|
name: Notify Pager Duty
|
94
|
-
command:
|
192
|
+
command: bundle exec y-notify "#eng-messaging-ops"
|
95
193
|
when: on_fail
|
96
194
|
- store_test_results:
|
97
195
|
path: "/tmp/test-results"
|
@@ -99,14 +197,47 @@ workflows:
|
|
99
197
|
version: 2
|
100
198
|
on-commit:
|
101
199
|
jobs:
|
102
|
-
-
|
200
|
+
- release:
|
201
|
+
context: org-global
|
202
|
+
requires:
|
203
|
+
- ruby-3.0.3-rails-7.0
|
204
|
+
- ruby-2.7.5-rails-7.0
|
205
|
+
- ruby-3.0.3-rails-6.1
|
206
|
+
- ruby-2.7.5-rails-6.1
|
207
|
+
filters:
|
208
|
+
tags:
|
209
|
+
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
|
210
|
+
branches:
|
211
|
+
ignore: /.*/
|
212
|
+
- generate-and-push-docs:
|
213
|
+
context: org-global
|
214
|
+
requires:
|
215
|
+
- release
|
216
|
+
filters:
|
217
|
+
tags:
|
218
|
+
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
|
219
|
+
branches:
|
220
|
+
ignore: /.*/
|
221
|
+
- ruby-3.0.3-rails-7.0:
|
103
222
|
context: org-global
|
104
|
-
|
223
|
+
filters:
|
224
|
+
tags:
|
225
|
+
only: &1 /.*/
|
226
|
+
- ruby-2.7.5-rails-7.0:
|
105
227
|
context: org-global
|
106
|
-
|
228
|
+
filters:
|
229
|
+
tags:
|
230
|
+
only: *1
|
231
|
+
- ruby-3.0.3-rails-6.1:
|
107
232
|
context: org-global
|
108
|
-
|
233
|
+
filters:
|
234
|
+
tags:
|
235
|
+
only: *1
|
236
|
+
- ruby-2.7.5-rails-6.1:
|
109
237
|
context: org-global
|
238
|
+
filters:
|
239
|
+
tags:
|
240
|
+
only: *1
|
110
241
|
scheduled:
|
111
242
|
triggers:
|
112
243
|
- schedule:
|
@@ -114,13 +245,13 @@ workflows:
|
|
114
245
|
filters:
|
115
246
|
branches:
|
116
247
|
only:
|
117
|
-
-
|
248
|
+
- main
|
118
249
|
jobs:
|
119
|
-
- ruby-
|
250
|
+
- ruby-3.0.3-rails-7.0:
|
120
251
|
context: org-global
|
121
|
-
- ruby-2.5
|
252
|
+
- ruby-2.7.5-rails-7.0:
|
122
253
|
context: org-global
|
123
|
-
- ruby-
|
254
|
+
- ruby-3.0.3-rails-6.1:
|
124
255
|
context: org-global
|
125
|
-
- ruby-2.5
|
256
|
+
- ruby-2.7.5-rails-6.1:
|
126
257
|
context: org-global
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
ruby-2.7.3
|
data/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @stitchfix/eng-messaging
|
data/Gemfile.rails-6.1
ADDED
data/Gemfile.rails-7.0
ADDED
data/README.md
CHANGED
@@ -148,8 +148,8 @@ Pwwka::Transmitter.send_message!(payload, routing_key, on_error: :ignore)
|
|
148
148
|
|
149
149
|
#### Delayed Messages
|
150
150
|
|
151
|
-
You might want to delay sending a message (for example, if you have just created a database
|
152
|
-
record and a race condition keeps catching you out). In that case you can use delayed message
|
151
|
+
You might want to delay sending a message (for example, if you have just created a database
|
152
|
+
record and a race condition keeps catching you out). In that case you can use delayed message
|
153
153
|
options:
|
154
154
|
|
155
155
|
```ruby
|
@@ -176,7 +176,12 @@ Pwwka.configure do |config|
|
|
176
176
|
end
|
177
177
|
```
|
178
178
|
|
179
|
-
Regardless of which processor you use, the name of the queue created is `pwwka_send_message_async`.
|
179
|
+
Regardless of which processor you use, the name of the queue created is `pwwka_send_message_async`. You will need to start a worker process to work the queue. For a `Procfile` setup, with Resque as the processor, that could look something like this:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
pwwka_send_message_async_worker: rake resque:work QUEUE=pwwka_send_message_async
|
183
|
+
```
|
184
|
+
|
180
185
|
|
181
186
|
You can also configure Pwwka to use your own custom job using the `async_job_klass` configuration option. An example might be:
|
182
187
|
```
|
@@ -191,7 +196,7 @@ If you are using Resque and `Resque::Plugins::ExponentialBackoff` is available,
|
|
191
196
|
|
192
197
|
#### Message Queuer
|
193
198
|
|
194
|
-
You can queue up messages and send them in a batch. This is most useful when multiple messages
|
199
|
+
You can queue up messages and send them in a batch. This is most useful when multiple messages
|
195
200
|
need to sent from within a transaction block.
|
196
201
|
|
197
202
|
For example:
|
@@ -255,7 +260,7 @@ Here is an example:
|
|
255
260
|
|
256
261
|
```ruby
|
257
262
|
class ClientIndexMessageHandler
|
258
|
-
|
263
|
+
|
259
264
|
def self.handle!(delivery_info, properties, payload)
|
260
265
|
handler.do_a_thing(payload)
|
261
266
|
end
|
@@ -430,7 +435,7 @@ If you use [Resque][resque], and you wish to handle messages in a resque job, yo
|
|
430
435
|
|
431
436
|
Note that you must provide `@queue` in your job. `QueueResqueJobHandler` doesn't support setting a custom queue at enqueue-time (PRs welcome :).
|
432
437
|
|
433
|
-
Note that if you were using this library before version 0.12.0, your job would only be given the payload. If you change your job to accept
|
438
|
+
Note that if you were using this library before version 0.12.0, your job would only be given the payload. If you change your job to accept exactly three arguments, you will be given the payload, routing key, and message properties. If any of those arguments are optional, you will need to set `PWWKA_QUEUE_EXTENDED_INFO` to `"true"` to force pwwka to pass those along. Without it, your job only gets the payload to avoid breaking legacy consumers.
|
434
439
|
|
435
440
|
3. Profit!
|
436
441
|
|
@@ -454,9 +459,9 @@ describe "my integration test" do
|
|
454
459
|
@test_handler.test_setup
|
455
460
|
end
|
456
461
|
|
457
|
-
after(:all) do
|
462
|
+
after(:all) do
|
458
463
|
# this clears out any messages, so you have a clean test environment next time
|
459
|
-
@test_handler.test_teardown
|
464
|
+
@test_handler.test_teardown
|
460
465
|
end
|
461
466
|
|
462
467
|
it "uses the message bus" do
|
@@ -527,6 +532,12 @@ Pwwka.configuration.payload_logging = :error # Only log payloads for ERROR or FA
|
|
527
532
|
Pwwka.configuration.payload_logging = :fatal # Only log payloads for FATAL messages
|
528
533
|
```
|
529
534
|
|
535
|
+
You can also hook into logging by passing a hash containing keys of strings to match and corresponding `Proc` objects for the logger to execute instead of logging a message. The `Proc` will be called with the original message string that was to be logged and the params specific for that log event. So, if for instance, you wanted to emit a count metric to your monitoring system instead of logging each processed message you could set the configuration:
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
Pwwka.configuration.log_hooks = { 'Processed Message on' => ->(message, params){ $stats.count('message_processed') } }
|
539
|
+
```
|
540
|
+
|
530
541
|
#### Manual monitoring
|
531
542
|
|
532
543
|
RabbitMQ has a web interface for checking out the health of connections, channels, exchanges and queues. Your RabbitMQ provider should
|
data/lib/pwwka/configuration.rb
CHANGED
@@ -10,6 +10,7 @@ module Pwwka
|
|
10
10
|
attr_accessor :delayed_exchange_name
|
11
11
|
attr_accessor :logger
|
12
12
|
attr_accessor :log_level
|
13
|
+
attr_accessor :log_hooks
|
13
14
|
attr_accessor :options
|
14
15
|
attr_accessor :background_job_processor
|
15
16
|
attr_accessor :send_message_resque_backoff_strategy
|
@@ -26,6 +27,7 @@ module Pwwka
|
|
26
27
|
@delayed_exchange_name = "pwwka.delayed.#{Pwwka.environment}"
|
27
28
|
@logger = MonoLogger.new(STDOUT)
|
28
29
|
@log_level = :info
|
30
|
+
@log_hooks = {}
|
29
31
|
@options = {}
|
30
32
|
@send_message_resque_backoff_strategy = [5, #intermittent glitch?
|
31
33
|
60, # quick interruption
|
@@ -45,10 +47,12 @@ module Pwwka
|
|
45
47
|
def app_id
|
46
48
|
if @app_id.to_s.strip == ""
|
47
49
|
if defined?(Rails)
|
48
|
-
if Rails.respond_to?(:application)
|
49
|
-
Rails.application.class
|
50
|
+
if Rails.respond_to?(:application) && Rails.respond_to?(:version)
|
51
|
+
app_klass = Rails.application.class
|
52
|
+
app_parent = app_klass.module_parent
|
53
|
+
app_parent.name
|
50
54
|
else
|
51
|
-
raise "'Rails' is defined, but it doesn't respond to #application, so could not derive the app_id; you must explicitly set it"
|
55
|
+
raise "'Rails' is defined, but it doesn't respond to #application or #version, so could not derive the app_id; you must explicitly set it"
|
52
56
|
end
|
53
57
|
else
|
54
58
|
raise "Could not derive the app_id; you must explicitly set it"
|
data/lib/pwwka/logging.rb
CHANGED
@@ -22,7 +22,10 @@ module Pwwka
|
|
22
22
|
params[:payload] = "[omitted]" if params[:payload]
|
23
23
|
end
|
24
24
|
message = format % params
|
25
|
-
|
25
|
+
|
26
|
+
if Pwwka.configuration.log_hooks.select { |key, _value| message.match key }.each { |_key, value| value.call(message, params) }.empty?
|
27
|
+
logger.send(level,message)
|
28
|
+
end
|
26
29
|
end
|
27
30
|
end
|
28
31
|
end
|
data/lib/pwwka/transmitter.rb
CHANGED
@@ -23,13 +23,20 @@ module Pwwka
|
|
23
23
|
|
24
24
|
DEFAULT_DELAY_BY_MS = 5000
|
25
25
|
|
26
|
+
attr_reader :caller_manages_connector
|
26
27
|
attr_reader :channel_connector
|
27
28
|
|
28
|
-
def initialize
|
29
|
-
|
29
|
+
def initialize(channel_connector: nil)
|
30
|
+
if channel_connector
|
31
|
+
@caller_manages_connector = true
|
32
|
+
@channel_connector = channel_connector
|
33
|
+
else
|
34
|
+
@caller_manages_connector = false
|
35
|
+
@channel_connector = ChannelConnector.new(connection_name: "p: #{Pwwka.configuration.app_id} #{Pwwka.configuration.process_name}".strip)
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
|
-
# Send an important message that must go through. This method allows any raised exception
|
39
|
+
# Send an important message that must go through. This method allows any raised exception
|
33
40
|
# to pass through.
|
34
41
|
#
|
35
42
|
# payload:: Hash of what you'd like to include in your message
|
@@ -54,11 +61,13 @@ module Pwwka
|
|
54
61
|
delay_by: nil,
|
55
62
|
type: nil,
|
56
63
|
message_id: :auto_generate,
|
57
|
-
headers: nil
|
64
|
+
headers: nil,
|
65
|
+
channel_connector: nil
|
66
|
+
)
|
58
67
|
if delayed
|
59
|
-
new.send_delayed_message!(*[payload, routing_key, delay_by].compact, type: type, headers: headers, message_id: message_id)
|
68
|
+
new(channel_connector: channel_connector).send_delayed_message!(*[payload, routing_key, delay_by].compact, type: type, headers: headers, message_id: message_id)
|
60
69
|
else
|
61
|
-
new.send_message!(payload, routing_key, type: type, headers: headers, message_id: message_id)
|
70
|
+
new(channel_connector: channel_connector).send_message!(payload, routing_key, type: type, headers: headers, message_id: message_id)
|
62
71
|
end
|
63
72
|
logf "AFTER Transmitting Message on %{routing_key} -> %{payload}",routing_key: routing_key, payload: payload
|
64
73
|
true
|
@@ -95,11 +104,24 @@ module Pwwka
|
|
95
104
|
job = Pwwka.configuration.async_job_klass
|
96
105
|
|
97
106
|
if background_job_processor == :resque
|
98
|
-
|
99
|
-
|
100
|
-
|
107
|
+
resque_args = [job, payload, routing_key]
|
108
|
+
|
109
|
+
unless type == nil && message_id == :auto_generate && headers == nil
|
110
|
+
# NOTE: (jdlubrano)
|
111
|
+
# Why can't we pass these options all of the time? Well, if a user
|
112
|
+
# of pwwka has configured their own async_job_klass that only has an
|
113
|
+
# arity of 2 (i.e. payload and routing key), then passing these options
|
114
|
+
# as an additional argument would break the user's application. In
|
115
|
+
# order to maintain compatibility with preceding versions of Pwwka,
|
116
|
+
# we need to ensure that the same arguments passed into this method
|
117
|
+
# result in compatible calls to enqueue any Resque jobs.
|
118
|
+
resque_args << { type: type, message_id: message_id, headers: headers }
|
119
|
+
end
|
120
|
+
|
121
|
+
if delay_by_ms.zero?
|
122
|
+
Resque.enqueue(*resque_args)
|
101
123
|
else
|
102
|
-
Resque.enqueue_in(delay_by_ms/1000,
|
124
|
+
Resque.enqueue_in(delay_by_ms/1000, *resque_args)
|
103
125
|
end
|
104
126
|
elsif background_job_processor == :sidekiq
|
105
127
|
options = { delay_by_ms: delay_by_ms, type: type, message_id: message_id, headers: headers }
|
@@ -134,7 +156,9 @@ module Pwwka
|
|
134
156
|
logf "END Transmitting Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
|
135
157
|
true
|
136
158
|
ensure
|
137
|
-
|
159
|
+
unless caller_manages_connector
|
160
|
+
channel_connector.connection_close
|
161
|
+
end
|
138
162
|
end
|
139
163
|
|
140
164
|
|
@@ -154,7 +178,9 @@ module Pwwka
|
|
154
178
|
logf "END Transmitting Delayed Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
|
155
179
|
true
|
156
180
|
ensure
|
157
|
-
|
181
|
+
unless caller_manages_connector
|
182
|
+
channel_connector.connection_close
|
183
|
+
end
|
158
184
|
end
|
159
185
|
|
160
186
|
end
|
data/lib/pwwka/version.rb
CHANGED
data/lib/pwwka.rb
CHANGED
@@ -27,7 +27,6 @@ require 'pwwka/channel_connector'
|
|
27
27
|
require 'pwwka/handling'
|
28
28
|
require 'pwwka/receiver'
|
29
29
|
require 'pwwka/transmitter'
|
30
|
-
require 'pwwka/persistent_transmitter'
|
31
30
|
require 'pwwka/message_queuer'
|
32
31
|
require 'pwwka/error_handlers'
|
33
32
|
require 'pwwka/configuration'
|
data/owners.json
CHANGED
data/pwwka.gemspec
CHANGED
@@ -20,13 +20,13 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
s.add_runtime_dependency("bunny")
|
23
|
-
s.add_runtime_dependency("activesupport")
|
23
|
+
s.add_runtime_dependency("activesupport", ">= 6.0.0")
|
24
24
|
s.add_runtime_dependency("activemodel")
|
25
25
|
s.add_runtime_dependency("mono_logger")
|
26
26
|
s.add_development_dependency("rake")
|
27
27
|
s.add_development_dependency("rspec")
|
28
28
|
s.add_development_dependency("resque")
|
29
|
-
s.add_development_dependency("resque-retry")
|
29
|
+
s.add_development_dependency("resque-retry", "~> 1.5.3")
|
30
30
|
s.add_development_dependency("sidekiq")
|
31
31
|
s.add_development_dependency("simplecov")
|
32
32
|
s.add_development_dependency("resqutils")
|
@@ -2,6 +2,7 @@ require 'spec_helper.rb'
|
|
2
2
|
require 'resqutils/spec/resque_helpers'
|
3
3
|
require 'resqutils/spec/resque_matchers'
|
4
4
|
require 'pwwka/queue_resque_job_handler'
|
5
|
+
require 'active_support/time'
|
5
6
|
|
6
7
|
require_relative "support/integration_test_setup"
|
7
8
|
require_relative "support/logging_receiver"
|
@@ -11,6 +12,9 @@ describe "sending and receiving messages", :integration do
|
|
11
12
|
include IntegrationTestHelpers
|
12
13
|
include Resqutils::Spec::ResqueHelpers
|
13
14
|
|
15
|
+
let(:async_resque_queue) { 'pwwka_send_message_async' }
|
16
|
+
let(:delayed_resque_queue) { :delayed }
|
17
|
+
|
14
18
|
before do
|
15
19
|
ENV["JOB_KLASS"] = MyTestJob.name
|
16
20
|
ENV["PWWKA_QUEUE_EXTENDED_INFO"] = "true"
|
@@ -30,7 +34,8 @@ describe "sending and receiving messages", :integration do
|
|
30
34
|
FooReceiver.reset!
|
31
35
|
MultiRoutingReceived.reset!
|
32
36
|
OtherFooReceiver.reset!
|
33
|
-
clear_queue(
|
37
|
+
clear_queue(async_resque_queue)
|
38
|
+
clear_queue(delayed_resque_queue)
|
34
39
|
clear_queue(MyTestJob)
|
35
40
|
end
|
36
41
|
|
@@ -144,7 +149,7 @@ describe "sending and receiving messages", :integration do
|
|
144
149
|
|
145
150
|
expect(AllReceiver.messages_received.size).to eq(0)
|
146
151
|
|
147
|
-
process_resque_job(Pwwka::SendMessageAsyncJob
|
152
|
+
process_resque_job(Pwwka::SendMessageAsyncJob, async_resque_queue)
|
148
153
|
|
149
154
|
allow_receivers_to_process_queues
|
150
155
|
|
@@ -166,7 +171,7 @@ describe "sending and receiving messages", :integration do
|
|
166
171
|
|
167
172
|
expect(AllReceiver.messages_received.size).to eq(0)
|
168
173
|
|
169
|
-
process_resque_job(Pwwka::SendMessageAsyncJob
|
174
|
+
process_resque_job(Pwwka::SendMessageAsyncJob, async_resque_queue)
|
170
175
|
|
171
176
|
allow_receivers_to_process_queues
|
172
177
|
|
@@ -186,12 +191,28 @@ describe "sending and receiving messages", :integration do
|
|
186
191
|
|
187
192
|
allow(Pwwka).to receive(:configuration).and_return(configuration)
|
188
193
|
|
189
|
-
allow(Resque).to receive(:
|
194
|
+
allow(Resque).to receive(:enqueue)
|
190
195
|
|
191
196
|
Pwwka::Transmitter.send_message_async({ sample: "payload", has: { deeply: true, nested: 4 }},
|
192
197
|
"pwwka.testing.bar")
|
193
198
|
|
194
|
-
expect(Resque).to have_received(:
|
199
|
+
expect(Resque).to have_received(:enqueue).with(async_job_klass, anything, anything)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "can queue a job to send a message with a delay" do
|
203
|
+
Pwwka::Transmitter.send_message_async({ sample: "payload" },
|
204
|
+
"pwwka.testing.bar",
|
205
|
+
delay_by_ms: 1_000)
|
206
|
+
|
207
|
+
allow_receivers_to_process_queues # not expecting anything to be processed
|
208
|
+
|
209
|
+
expect(AllReceiver.messages_received.size).to eq(0)
|
210
|
+
|
211
|
+
process_resque_job(Pwwka::SendMessageAsyncJob, delayed_resque_queue)
|
212
|
+
|
213
|
+
allow_receivers_to_process_queues
|
214
|
+
|
215
|
+
expect(AllReceiver.messages_received.size).to eq(1)
|
195
216
|
end
|
196
217
|
end
|
197
218
|
|
data/spec/spec_helper.rb
CHANGED
@@ -11,7 +11,12 @@ end
|
|
11
11
|
|
12
12
|
require 'pwwka'
|
13
13
|
require 'pwwka/test_handler'
|
14
|
-
|
14
|
+
begin
|
15
|
+
require 'active_support/core_ext/hash'
|
16
|
+
rescue NameError
|
17
|
+
require "active_support/isolated_execution_state"
|
18
|
+
require 'active_support/core_ext/hash'
|
19
|
+
end
|
15
20
|
|
16
21
|
# These are required in pwwka proper, but they are guarded to not cause
|
17
22
|
# an error if missing. Requiring here so their absence will fail the tests
|
@@ -26,7 +31,7 @@ test_configuration = TestConfiguration.new(File.join(GEM_ROOT,"docker-compose.ym
|
|
26
31
|
RSpec.configure do |config|
|
27
32
|
|
28
33
|
config.expect_with :rspec do |c|
|
29
|
-
c.syntax = [:should,:expect] # should is needed to make a resque helper
|
34
|
+
c.syntax = [:should,:expect] # should is needed to make a resque helper
|
30
35
|
# from resqutils work
|
31
36
|
end
|
32
37
|
|
@@ -75,6 +75,14 @@ describe Pwwka::Configuration do
|
|
75
75
|
def self.application
|
76
76
|
MyAmazingApp::Application.new
|
77
77
|
end
|
78
|
+
|
79
|
+
def self.version
|
80
|
+
active_support_dependency = Bundler.locked_gems.dependencies.detect do |name, dep|
|
81
|
+
name == "activesupport"
|
82
|
+
end.last
|
83
|
+
version_specification = active_support_dependency.requirement.to_s
|
84
|
+
version_specification[/\d.+/]
|
85
|
+
end
|
78
86
|
end
|
79
87
|
Object.const_set("Rails",rails)
|
80
88
|
end
|
@@ -97,7 +105,7 @@ describe Pwwka::Configuration do
|
|
97
105
|
it "blows up when not set" do
|
98
106
|
expect {
|
99
107
|
configuration.app_id
|
100
|
-
}.to raise_error(/'Rails' is defined, but it doesn't respond to #application, so could not derive the app_id; you must explicitly set it/)
|
108
|
+
}.to raise_error(/'Rails' is defined, but it doesn't respond to #application or #version, so could not derive the app_id; you must explicitly set it/)
|
101
109
|
end
|
102
110
|
end
|
103
111
|
end
|
data/spec/unit/logging_spec.rb
CHANGED
@@ -93,6 +93,44 @@ describe Pwwka::Logging do
|
|
93
93
|
expect(logger).to have_received(:error).with("This is also the payload: [omitted]")
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
context "log_hook matching" do
|
98
|
+
def test_func(message, params)
|
99
|
+
end
|
100
|
+
|
101
|
+
before do
|
102
|
+
Pwwka.configuration.log_hooks = { "test message" => ->(message, params){ test_func(message, params) } }
|
103
|
+
end
|
104
|
+
|
105
|
+
after do
|
106
|
+
Pwwka.configuration.log_hooks = {}
|
107
|
+
end
|
108
|
+
|
109
|
+
context "message matches hook" do
|
110
|
+
it "overrides logging" do
|
111
|
+
ForLogging.logf("test message", {})
|
112
|
+
|
113
|
+
expect(logger).not_to have_received(:info)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "calls the hook" do
|
117
|
+
allow(self).to receive(:test_func)
|
118
|
+
test_params = { param: :test }
|
119
|
+
|
120
|
+
ForLogging.logf("test message", test_params)
|
121
|
+
|
122
|
+
expect(self).to have_received(:test_func).with("test message", test_params)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "message doesn't match hook" do
|
127
|
+
it "logs as normal" do
|
128
|
+
ForLogging.logf("other message", {})
|
129
|
+
|
130
|
+
expect(logger).to have_received(:info).with("other message")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
96
134
|
end
|
97
135
|
|
98
136
|
end
|
@@ -312,19 +312,19 @@ describe Pwwka::Transmitter do
|
|
312
312
|
end
|
313
313
|
context "on_error: :resque" do
|
314
314
|
it "queues a Resque job" do
|
315
|
-
allow(Resque).to receive(:
|
315
|
+
allow(Resque).to receive(:enqueue)
|
316
316
|
described_class.send_message!(payload,routing_key, on_error: :resque)
|
317
|
-
expect(Resque).to have_received(:
|
317
|
+
expect(Resque).to have_received(:enqueue).with(Pwwka::SendMessageAsyncJob,payload,routing_key)
|
318
318
|
end
|
319
319
|
context "when there is a problem queueing the resque job" do
|
320
320
|
it "raises the original exception job" do
|
321
|
-
allow(Resque).to receive(:
|
321
|
+
allow(Resque).to receive(:enqueue).and_raise("NOPE")
|
322
322
|
expect {
|
323
323
|
described_class.send_message!(payload,routing_key, on_error: :resque)
|
324
324
|
}.to raise_error(/OH NOES/)
|
325
325
|
end
|
326
326
|
it "logs the Resque error as a warning" do
|
327
|
-
allow(Resque).to receive(:
|
327
|
+
allow(Resque).to receive(:enqueue).and_raise("NOPE")
|
328
328
|
begin
|
329
329
|
described_class.send_message!(payload,routing_key, on_error: :resque)
|
330
330
|
rescue => ex
|
@@ -338,18 +338,18 @@ describe Pwwka::Transmitter do
|
|
338
338
|
context "when configured background_job_processor is Resque" do
|
339
339
|
context "when the job is queued successfully" do
|
340
340
|
before do
|
341
|
-
allow(Resque).to receive(:
|
341
|
+
allow(Resque).to receive(:enqueue)
|
342
342
|
end
|
343
343
|
|
344
344
|
it "queues a Resque job" do
|
345
345
|
described_class.send_message!(payload, routing_key, on_error: :retry_async)
|
346
|
-
expect(Resque).to have_received(:
|
346
|
+
expect(Resque).to have_received(:enqueue).with(Pwwka::SendMessageAsyncJob, payload, routing_key)
|
347
347
|
end
|
348
348
|
end
|
349
349
|
|
350
350
|
context "when there is a problem queueing the Resque job" do
|
351
351
|
before do
|
352
|
-
allow(Resque).to receive(:
|
352
|
+
allow(Resque).to receive(:enqueue).and_raise("NOPE")
|
353
353
|
end
|
354
354
|
|
355
355
|
it "raises the original exception job" do
|
@@ -576,5 +576,41 @@ describe Pwwka::Transmitter do
|
|
576
576
|
end
|
577
577
|
end
|
578
578
|
end
|
579
|
-
end
|
580
579
|
|
580
|
+
context "application manages connection" do
|
581
|
+
let(:managed_connector) { instance_double(Pwwka::ChannelConnector,
|
582
|
+
topic_exchange: double(:topic_exchange).as_null_object,
|
583
|
+
delayed_exchange: double(:delayed_exchange).as_null_object
|
584
|
+
).as_null_object }
|
585
|
+
describe ".send_message!" do
|
586
|
+
|
587
|
+
context "send immediate" do
|
588
|
+
it "doesn't open a new connection" do
|
589
|
+
described_class.send_message!(payload, routing_key, delayed: false, channel_connector: managed_connector)
|
590
|
+
|
591
|
+
expect(Pwwka::ChannelConnector).not_to have_received(:new)
|
592
|
+
end
|
593
|
+
|
594
|
+
it "doesn't close a passed in connection" do
|
595
|
+
described_class.send_message!(payload, routing_key, delayed: false, channel_connector: managed_connector)
|
596
|
+
|
597
|
+
expect(managed_connector).not_to have_received(:connection_close)
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
context "send delayed" do
|
602
|
+
it "doesn't open a new connection" do
|
603
|
+
described_class.send_message!(payload, routing_key, delayed: true, channel_connector: managed_connector)
|
604
|
+
|
605
|
+
expect(Pwwka::ChannelConnector).not_to have_received(:new)
|
606
|
+
end
|
607
|
+
|
608
|
+
it "doesn't close a passed in connection" do
|
609
|
+
described_class.send_message!(payload, routing_key, delayed: true, channel_connector: managed_connector)
|
610
|
+
|
611
|
+
expect(managed_connector).not_to have_received(:connection_close)
|
612
|
+
end
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwwka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.RC1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stitch Fix Engineering
|
@@ -12,10 +12,10 @@ authors:
|
|
12
12
|
- Jonathan Dean
|
13
13
|
- Nick Reavill
|
14
14
|
- Simeon Willbanks
|
15
|
-
autorequire:
|
15
|
+
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date:
|
18
|
+
date: 2022-01-27 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bunny
|
@@ -37,14 +37,14 @@ dependencies:
|
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 6.0.0
|
41
41
|
type: :runtime
|
42
42
|
prerelease: false
|
43
43
|
version_requirements: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 6.0.0
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: activemodel
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,16 +119,16 @@ dependencies:
|
|
119
119
|
name: resque-retry
|
120
120
|
requirement: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - "
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
124
|
+
version: 1.5.3
|
125
125
|
type: :development
|
126
126
|
prerelease: false
|
127
127
|
version_requirements: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
131
|
+
version: 1.5.3
|
132
132
|
- !ruby/object:Gem::Dependency
|
133
133
|
name: sidekiq
|
134
134
|
requirement: !ruby/object:Gem::Requirement
|
@@ -235,13 +235,12 @@ files:
|
|
235
235
|
- ".ruby-gemset"
|
236
236
|
- ".ruby-version"
|
237
237
|
- ".travis.yml"
|
238
|
+
- CODEOWNERS
|
238
239
|
- CODE_OF_CONDUCT.md
|
239
240
|
- CONTRIBUTING.md
|
240
241
|
- Gemfile
|
241
|
-
- Gemfile.rails-
|
242
|
-
- Gemfile.rails-
|
243
|
-
- Gemfile.rails-5.1
|
244
|
-
- Gemfile.rails-5.2
|
242
|
+
- Gemfile.rails-6.1
|
243
|
+
- Gemfile.rails-7.0
|
245
244
|
- LICENSE
|
246
245
|
- README.md
|
247
246
|
- Rakefile
|
@@ -263,7 +262,6 @@ files:
|
|
263
262
|
- lib/pwwka/handling.rb
|
264
263
|
- lib/pwwka/logging.rb
|
265
264
|
- lib/pwwka/message_queuer.rb
|
266
|
-
- lib/pwwka/persistent_transmitter.rb
|
267
265
|
- lib/pwwka/publish_options.rb
|
268
266
|
- lib/pwwka/queue_resque_job_handler.rb
|
269
267
|
- lib/pwwka/receiver.rb
|
@@ -293,7 +291,6 @@ files:
|
|
293
291
|
- spec/unit/configuration_spec.rb
|
294
292
|
- spec/unit/logging_spec.rb
|
295
293
|
- spec/unit/message_queuer_spec.rb
|
296
|
-
- spec/unit/persistent_transmitter_spec.rb
|
297
294
|
- spec/unit/queue_resque_job_handler_spec.rb
|
298
295
|
- spec/unit/receiver_spec.rb
|
299
296
|
- spec/unit/send_message_async_job_spec.rb
|
@@ -304,7 +301,7 @@ homepage: https://github.com/stitchfix/pwwka
|
|
304
301
|
licenses:
|
305
302
|
- MIT
|
306
303
|
metadata: {}
|
307
|
-
post_install_message:
|
304
|
+
post_install_message:
|
308
305
|
rdoc_options: []
|
309
306
|
require_paths:
|
310
307
|
- lib
|
@@ -319,9 +316,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
319
316
|
- !ruby/object:Gem::Version
|
320
317
|
version: 1.3.1
|
321
318
|
requirements: []
|
322
|
-
|
323
|
-
|
324
|
-
signing_key:
|
319
|
+
rubygems_version: 3.1.6
|
320
|
+
signing_key:
|
325
321
|
specification_version: 4
|
326
322
|
summary: Send and receive messages via RabbitMQ
|
327
323
|
test_files:
|
@@ -343,7 +339,6 @@ test_files:
|
|
343
339
|
- spec/unit/configuration_spec.rb
|
344
340
|
- spec/unit/logging_spec.rb
|
345
341
|
- spec/unit/message_queuer_spec.rb
|
346
|
-
- spec/unit/persistent_transmitter_spec.rb
|
347
342
|
- spec/unit/queue_resque_job_handler_spec.rb
|
348
343
|
- spec/unit/receiver_spec.rb
|
349
344
|
- spec/unit/send_message_async_job_spec.rb
|
data/Gemfile.rails-4.2
DELETED
data/Gemfile.rails-5.0
DELETED
data/Gemfile.rails-5.1
DELETED
data/Gemfile.rails-5.2
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require_relative "publish_options"
|
2
|
-
|
3
|
-
begin # optional dependency
|
4
|
-
require 'resque'
|
5
|
-
require 'resque-retry'
|
6
|
-
rescue LoadError
|
7
|
-
end
|
8
|
-
|
9
|
-
module Pwwka
|
10
|
-
# Primary interface for sending messages.
|
11
|
-
#
|
12
|
-
# Example:
|
13
|
-
#
|
14
|
-
# # Send a message, blowing up if there's any problem
|
15
|
-
# Pwwka::PersistentTransmitter.batch do |transmitter|
|
16
|
-
# transmitter.send_message!({ user_id: @user.id }, "users.user.activated")
|
17
|
-
# end
|
18
|
-
|
19
|
-
class PersistentTransmitter
|
20
|
-
|
21
|
-
extend Pwwka::Logging
|
22
|
-
include Pwwka::Logging
|
23
|
-
|
24
|
-
DEFAULT_DELAY_BY_MS = 5000
|
25
|
-
|
26
|
-
attr_reader :channel_connector
|
27
|
-
|
28
|
-
def initialize
|
29
|
-
@channel_connector = ChannelConnector.new(connection_name: "p: #{Pwwka.configuration.app_id} #{Pwwka.configuration.process_name}".strip)
|
30
|
-
end
|
31
|
-
|
32
|
-
def send_message!(payload, routing_key, type: nil, headers: nil, message_id: :auto_generate)
|
33
|
-
publish_options = Pwwka::PublishOptions.new(
|
34
|
-
routing_key: routing_key,
|
35
|
-
message_id: message_id,
|
36
|
-
type: type,
|
37
|
-
headers: headers
|
38
|
-
)
|
39
|
-
logf "START Transmitting Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
|
40
|
-
channel_connector.topic_exchange.publish(payload.to_json, publish_options.to_h)
|
41
|
-
# if it gets this far it has succeeded
|
42
|
-
logf "END Transmitting Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
|
43
|
-
true
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
class << self
|
48
|
-
private :new
|
49
|
-
|
50
|
-
def batch
|
51
|
-
transmitter = new
|
52
|
-
yield(transmitter)
|
53
|
-
ensure
|
54
|
-
transmitter.channel_connector.connection_close
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,153 +0,0 @@
|
|
1
|
-
require 'spec_helper.rb'
|
2
|
-
|
3
|
-
describe Pwwka::PersistentTransmitter do
|
4
|
-
let(:topic_exchange) { double("topic exchange") }
|
5
|
-
let(:delayed_exchange) { double("delayed exchange") }
|
6
|
-
let(:channel_connector) { instance_double(Pwwka::ChannelConnector, topic_exchange: topic_exchange, delayed_exchange: delayed_exchange) }
|
7
|
-
let(:logger) { double(Logger) }
|
8
|
-
let(:payload) {
|
9
|
-
{
|
10
|
-
foo: { bar: "blah" },
|
11
|
-
crud: 12,
|
12
|
-
}
|
13
|
-
}
|
14
|
-
let(:routing_key) { "sf.foo.bar" }
|
15
|
-
|
16
|
-
|
17
|
-
before do
|
18
|
-
@original_logger = Pwwka.configuration.logger
|
19
|
-
Pwwka.configuration.logger = logger
|
20
|
-
allow(logger).to receive(:info)
|
21
|
-
allow(logger).to receive(:warn)
|
22
|
-
allow(logger).to receive(:error)
|
23
|
-
allow(Pwwka::ChannelConnector).to receive(:new).with(connection_name: "p: MyAwesomeApp my_awesome_process").and_return(channel_connector)
|
24
|
-
allow(channel_connector).to receive(:connection_close)
|
25
|
-
allow(topic_exchange).to receive(:publish)
|
26
|
-
allow(delayed_exchange).to receive(:publish)
|
27
|
-
end
|
28
|
-
|
29
|
-
after do
|
30
|
-
Pwwka.configuration.logger = @original_logger
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
shared_examples "it sends standard and overridden data to the exchange" do
|
35
|
-
it "publishes to the topic exchange" do
|
36
|
-
expect(exchange).to have_received(:publish).with(payload.to_json, kind_of(Hash))
|
37
|
-
end
|
38
|
-
|
39
|
-
it "passes the routing key" do
|
40
|
-
expect(exchange).to have_received(:publish).with(
|
41
|
-
payload.to_json,
|
42
|
-
hash_including(routing_key: routing_key))
|
43
|
-
end
|
44
|
-
|
45
|
-
it "sets the type" do
|
46
|
-
expect(exchange).to have_received(:publish).with(
|
47
|
-
payload.to_json,
|
48
|
-
hash_including(type: "Customer"))
|
49
|
-
end
|
50
|
-
|
51
|
-
it "sets the headers" do
|
52
|
-
expect(exchange).to have_received(:publish).with(
|
53
|
-
payload.to_json,
|
54
|
-
hash_including(headers: { "custom" => "value", "other_custom" => "other_value" }))
|
55
|
-
end
|
56
|
-
|
57
|
-
it "uses the overridden message id" do
|
58
|
-
expect(exchange).to have_received(:publish).with(
|
59
|
-
payload.to_json,
|
60
|
-
hash_including(message_id: "snowflake id that is likely a bad idea, but if you must"))
|
61
|
-
end
|
62
|
-
|
63
|
-
it "sets the app id to what's configured" do
|
64
|
-
expect(exchange).to have_received(:publish).with(
|
65
|
-
payload.to_json,
|
66
|
-
hash_including(app_id: "MyAwesomeApp"))
|
67
|
-
end
|
68
|
-
|
69
|
-
it "sets the content type to JSON with a version" do
|
70
|
-
expect(exchange).to have_received(:publish).with(
|
71
|
-
payload.to_json,
|
72
|
-
hash_including(content_type: "application/json; version=1"))
|
73
|
-
end
|
74
|
-
|
75
|
-
it "sets persistent true" do
|
76
|
-
expect(exchange).to have_received(:publish).with(
|
77
|
-
payload.to_json,
|
78
|
-
hash_including(persistent: true))
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
context "no new instance creation" do
|
84
|
-
it "doesn't allow creation of new instances unless inside the batch method" do
|
85
|
-
expect{ Pwwka::PersistentTransmitter.new }.to raise_error
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "#batch" do
|
90
|
-
context "Logging" do
|
91
|
-
it "logs the start and end of the transmission" do
|
92
|
-
described_class.batch do |transmitter|
|
93
|
-
transmitter.send_message!(payload,routing_key)
|
94
|
-
end
|
95
|
-
expect(logger).to have_received(:info).with(/START Transmitting Message on id\[[\w\-\d]+\] #{routing_key} ->/)
|
96
|
-
expect(logger).to have_received(:info).with(/END Transmitting Message on id\[[\w\-\d]+\] #{routing_key} ->/)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
it "closes the channel connector" do
|
101
|
-
described_class.batch do |transmitter|
|
102
|
-
transmitter.send_message!(payload,routing_key)
|
103
|
-
end
|
104
|
-
expect(channel_connector).to have_received(:connection_close)
|
105
|
-
end
|
106
|
-
|
107
|
-
it "only uses one connection" do
|
108
|
-
described_class.batch do |transmitter|
|
109
|
-
10.times do
|
110
|
-
transmitter.send_message!(payload,routing_key)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
expect(channel_connector).to have_received(:connection_close).once
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
context 'when an error is raised' do
|
118
|
-
|
119
|
-
let(:error) { 'oh no' }
|
120
|
-
|
121
|
-
before do
|
122
|
-
allow(topic_exchange).to receive(:publish).and_raise(error)
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'should raise the error and still close the channel_connector' do
|
126
|
-
expect { described_class.batch do |transmitter|
|
127
|
-
transmitter.send_message!(payload,routing_key)
|
128
|
-
end } .to raise_error(error)
|
129
|
-
expect(channel_connector).to have_received(:connection_close)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
context "with everything overridden" do
|
134
|
-
before do
|
135
|
-
described_class.batch do |transmitter|
|
136
|
-
transmitter.send_message!(
|
137
|
-
payload,
|
138
|
-
routing_key,
|
139
|
-
message_id: "snowflake id that is likely a bad idea, but if you must",
|
140
|
-
type: "Customer",
|
141
|
-
headers: {
|
142
|
-
"custom" => "value",
|
143
|
-
"other_custom" => "other_value",
|
144
|
-
})
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
it_behaves_like "it sends standard and overridden data to the exchange" do
|
149
|
-
let(:exchange) { topic_exchange }
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
end
|