sqewer 6.4.1 → 8.0.1
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 +0 -16
- data/CHANGELOG.md +21 -1
- data/README.md +17 -13
- data/bin/console +8 -0
- data/lib/sqewer.rb +5 -0
- data/lib/sqewer/cli.rb +1 -0
- data/lib/sqewer/connection.rb +47 -15
- data/lib/sqewer/simple_job.rb +8 -1
- data/lib/sqewer/version.rb +1 -1
- data/lib/sqewer/worker.rb +6 -3
- data/sqewer.gemspec +2 -0
- metadata +20 -5
- data/gemfiles/Gemfile.rails-4.2.x +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db608a0341020c8df0186ebc598164f5efef1c75051b4661aabb6e8c7e5c4406
|
4
|
+
data.tar.gz: 3823ade5a67c8e66844eed3e267f5d5c4f0b6f3626c53c645d22ebb57b25ed12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c549285412294f21ec5a8af1d5614e949941996c687b91478c5a1ed4553995e888aa56443dde5c6eace899b24d44d5a02e21dfb61d391408e126c01b001e3dd
|
7
|
+
data.tar.gz: 49b1d928b6786d38911db7803498a42fd4860c8c7723ec09a477b464103eded17a752d3f900c01f20af5cd0d6d79360d260d78a7636a0a8c1f7e6e322554e209
|
data/.travis.yml
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
gemfile:
|
2
|
-
- gemfiles/Gemfile.rails-4.2.x
|
3
2
|
- gemfiles/Gemfile.rails-5.0.x
|
4
3
|
- gemfiles/Gemfile.rails-5.1.x
|
5
4
|
rvm:
|
6
|
-
- 2.3.7
|
7
|
-
- 2.4.5
|
8
|
-
- 2.5.1
|
9
5
|
- 2.6.5
|
10
6
|
- 2.7.0
|
11
7
|
cache: bundler
|
@@ -13,15 +9,3 @@ sudo: false
|
|
13
9
|
env:
|
14
10
|
global:
|
15
11
|
- AWS_REGION=eu-central-1
|
16
|
-
matrix:
|
17
|
-
exclude:
|
18
|
-
- rvm: 2.3.7
|
19
|
-
gemfile: gemfiles/Gemfile.rails-5.0.x
|
20
|
-
- rvm: 2.3.7
|
21
|
-
gemfile: gemfiles/Gemfile.rails-5.1.x
|
22
|
-
- rvm: 2.5.1
|
23
|
-
gemfile: gemfiles/Gemfile.rails-4.2.x
|
24
|
-
- rvm: 2.6.5
|
25
|
-
gemfile: gemfiles/Gemfile.rails-4.2.x
|
26
|
-
- rvm: 2.7.0
|
27
|
-
gemfile: gemfiles/Gemfile.rails-4.2.x
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
|
+
### 8.0.1
|
2
|
+
- Release the singleton SQS client when AWS raises credentials error to be able to use a new credential next time
|
3
|
+
|
4
|
+
### 8.0.0
|
5
|
+
- Remove method `Sqewer.client=`
|
6
|
+
- Change `Sqewer::Connection` to use a singleton SQS client by default
|
7
|
+
|
8
|
+
### 7.0.0
|
9
|
+
- Remove support of Ruby 2.3, 2.4 and 2.5
|
10
|
+
- Remove support of Rails 4
|
11
|
+
- Change `Sqewer::Connection` to preferentially use a singleton instance of `Aws::SQS::Client`, which can be set using `Sqewer.client=`. This avoids many HTTP requests to the AWS metadata endpoint when getting credentials.
|
12
|
+
|
13
|
+
### 6.5.1
|
14
|
+
- Also retry on `Aws::SQS::Errors::InternalError` exception when receiving/sending messages. This will make
|
15
|
+
the receiving thread more resilient to sudden SQS failures. By the time SQS recovers the receiving thread
|
16
|
+
should stay alive.
|
17
|
+
|
18
|
+
### 6.5.0
|
19
|
+
- Adds `$stdout.sync = true` to CLI to flush the logs to STDOUT
|
20
|
+
|
1
21
|
### 6.4.1
|
2
|
-
- Retrieve attributes when receiving messages from SQS
|
22
|
+
- Retrieve attributes when receiving messages from SQS
|
3
23
|
|
4
24
|
### 6.4.0
|
5
25
|
- Raise an exception in submit! if the job serializes to a message that is
|
data/README.md
CHANGED
@@ -20,14 +20,14 @@ and to start processing, in your commandline handler:
|
|
20
20
|
|
21
21
|
#!/usr/bin/env ruby
|
22
22
|
require 'my_applicaion'
|
23
|
-
Sqewer::CLI.
|
23
|
+
Sqewer::CLI.start
|
24
24
|
|
25
25
|
To add arguments to the job
|
26
26
|
|
27
27
|
class JobWithArgs
|
28
28
|
include Sqewer::SimpleJob
|
29
29
|
attr_accessor :times
|
30
|
-
|
30
|
+
|
31
31
|
def run
|
32
32
|
...
|
33
33
|
end
|
@@ -48,7 +48,7 @@ The messages will only be deleted from SQS once the job execution completes with
|
|
48
48
|
|
49
49
|
## Requirements
|
50
50
|
|
51
|
-
Ruby 2.
|
51
|
+
Ruby 2.6+, version 2 of the AWS SDK. You can also run Sqewer backed by a SQLite database file, which can be handy for development situations.
|
52
52
|
|
53
53
|
## Job storage
|
54
54
|
|
@@ -88,6 +88,10 @@ Note that at this point only arguments that are raw JSON types are supported:
|
|
88
88
|
|
89
89
|
If you need marshalable Ruby types there instead, you might need to implement a custom `Serializer.`
|
90
90
|
|
91
|
+
### Sqewer::SimpleJob
|
92
|
+
|
93
|
+
The module `Sqewer::SimpleJob` can be included to a job class to add some features, specially dealing with attributes, see more details [here](https://github.com/WeTransfer/sqewer/blob/master/lib/sqewer/simple_job.rb).
|
94
|
+
|
91
95
|
## Jobs spawning dependent jobs
|
92
96
|
|
93
97
|
If your `run` method on the job object accepts arguments (has non-zero `arity` ) the `ExecutionContext` will
|
@@ -119,11 +123,11 @@ include all the keyword arguments needed to instantiate the job when executing.
|
|
119
123
|
def initialize(to:, body:)
|
120
124
|
...
|
121
125
|
end
|
122
|
-
|
126
|
+
|
123
127
|
def run()
|
124
128
|
...
|
125
129
|
end
|
126
|
-
|
130
|
+
|
127
131
|
def to_h
|
128
132
|
{to: @to, body: @body}
|
129
133
|
end
|
@@ -151,7 +155,7 @@ conform to the job serialization format used internally. For example, you can ha
|
|
151
155
|
message = JSON.load(message_blob)
|
152
156
|
return if message['Service'] # AWS test
|
153
157
|
return HandleS3Notification.new(message) if message['Records']
|
154
|
-
|
158
|
+
|
155
159
|
super # as default
|
156
160
|
end
|
157
161
|
end
|
@@ -176,7 +180,7 @@ The very minimal executable for running jobs would be this:
|
|
176
180
|
|
177
181
|
#!/usr/bin/env ruby
|
178
182
|
require 'my_applicaion'
|
179
|
-
Sqewer::CLI.
|
183
|
+
Sqewer::CLI.start
|
180
184
|
|
181
185
|
This will connect to the queue at the URL set in the `SQS_QUEUE_URL` environment variable, and
|
182
186
|
use all the default parameters. The `CLI` module will also set up a signal handler to terminate
|
@@ -233,9 +237,9 @@ you generate. For example, you could use a pipe. But in a more general case some
|
|
233
237
|
ActiveRAMGobbler.fetch_stupendously_many_things.each do |...|
|
234
238
|
end
|
235
239
|
end
|
236
|
-
|
240
|
+
|
237
241
|
_, status = Process.wait2(pid)
|
238
|
-
|
242
|
+
|
239
243
|
# Raise an error in the parent process to signal Sqewer that the job failed
|
240
244
|
# if the child exited with a non-0 status
|
241
245
|
raise "Child process crashed" unless status.exitstatus && status.exitstatus.zero?
|
@@ -252,7 +256,7 @@ You can wrap job processing in middleware. A full-featured middleware class look
|
|
252
256
|
# msg_id is the receipt handle, msg_payload is the message body string, msg_attributes are the message's attributes
|
253
257
|
yield
|
254
258
|
end
|
255
|
-
|
259
|
+
|
256
260
|
# Surrounds the actual job execution
|
257
261
|
def around_execution(job, context)
|
258
262
|
# job is the actual job you will be running, context is the ExecutionContext.
|
@@ -284,7 +288,7 @@ and traceable (make good use of logging).
|
|
284
288
|
|
285
289
|
# Usage with Rails via ActiveJob
|
286
290
|
|
287
|
-
This gem includes a queue adapter for usage with ActiveJob in Rails
|
291
|
+
This gem includes a queue adapter for usage with ActiveJob in Rails 5+. The functionality
|
288
292
|
is well-tested and should function for any well-conforming ActiveJob subclasses.
|
289
293
|
|
290
294
|
To run the default `sqewer` worker setup against your Rails application, first set it as the
|
@@ -378,7 +382,7 @@ products using this library, was a very bad idea (more workload for deployment).
|
|
378
382
|
|
379
383
|
## Why so many configurable components?
|
380
384
|
|
381
|
-
Because sometimes your requirements differ just-a-little-bit from what is provided, and you have to swap your
|
385
|
+
Because sometimes your requirements differ just-a-little-bit from what is provided, and you have to swap your
|
382
386
|
implementation in instead. One product needs foreign-submitted SQS jobs (S3 notifications). Another product
|
383
387
|
needs a custom Logger subclass. Yet another product needs process-based concurrency on top of threads.
|
384
388
|
Yet another process needs to manage database connections when running the jobs. Have 3-4 of those, and a
|
@@ -398,7 +402,7 @@ Because I found that a producer-consumer model with a thread pool works quite we
|
|
398
402
|
the Ruby standard library alone.
|
399
403
|
|
400
404
|
## Contributing to the library
|
401
|
-
|
405
|
+
|
402
406
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
403
407
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
404
408
|
* Fork the project.
|
data/bin/console
ADDED
data/lib/sqewer.rb
CHANGED
data/lib/sqewer/cli.rb
CHANGED
data/lib/sqewer/connection.rb
CHANGED
@@ -39,12 +39,25 @@ class Sqewer::Connection
|
|
39
39
|
raise "SQS_QUEUE_URL not set in the environment. This is the queue URL Sqewer uses by default."
|
40
40
|
end
|
41
41
|
|
42
|
+
# Returns a singleton of Aws::SQS::Client
|
43
|
+
def self.client
|
44
|
+
# It's better using a singleton client to prevent making a lot of HTTP
|
45
|
+
# requests to the AWS metadata endpoint when getting credentials.
|
46
|
+
@client ||= begin
|
47
|
+
require 'aws-sdk-sqs'
|
48
|
+
::Aws::SQS::Client.new(
|
49
|
+
instance_profile_credentials_timeout: 1,
|
50
|
+
instance_profile_credentials_retries: 5,
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
42
55
|
# Initializes a new adapter, with access to the SQS queue at the given URL.
|
43
56
|
#
|
44
57
|
# @param queue_url[String] the SQS queue URL (the URL can be copied from your AWS console)
|
45
|
-
def initialize(queue_url)
|
46
|
-
require 'aws-sdk-sqs'
|
58
|
+
def initialize(queue_url, client: self.class.client)
|
47
59
|
@queue_url = queue_url
|
60
|
+
@client = client
|
48
61
|
end
|
49
62
|
|
50
63
|
# Receive at most 10 messages from the queue, and return the array of Message objects. Retries for at
|
@@ -52,10 +65,10 @@ class Sqewer::Connection
|
|
52
65
|
# even after 15 minutes it is either down or the server is misconfigured. Either way it makes no sense to
|
53
66
|
# continue.
|
54
67
|
#
|
55
|
-
# @return [Array<Message>] an array of Message objects
|
68
|
+
# @return [Array<Message>] an array of Message objects
|
56
69
|
def receive_messages
|
57
|
-
Retriable.retriable on:
|
58
|
-
response = client.receive_message(
|
70
|
+
Retriable.retriable on: network_and_aws_sdk_errors, tries: MAX_RANDOM_RECEIVE_FAILURES do
|
71
|
+
response = @client.receive_message(
|
59
72
|
queue_url: @queue_url,
|
60
73
|
attribute_names: ['All'],
|
61
74
|
wait_time_seconds: DEFAULT_TIMEOUT_SECONDS,
|
@@ -63,13 +76,21 @@ class Sqewer::Connection
|
|
63
76
|
)
|
64
77
|
response.messages.map {|message| Message.new(message.receipt_handle, message.body, message.attributes) }
|
65
78
|
end
|
79
|
+
rescue Aws::Errors::MissingCredentialsError
|
80
|
+
# We noticed cases where errors related to AWS credentials started to happen suddenly.
|
81
|
+
# We don't know the root cause yet, but what we can do is release the
|
82
|
+
# singleton @client instance because it contains a cache of credentials that in most
|
83
|
+
# cases is no longer valid.
|
84
|
+
self.class.release_client
|
85
|
+
|
86
|
+
raise
|
66
87
|
end
|
67
88
|
|
68
89
|
# Send a message to the backing queue
|
69
90
|
#
|
70
91
|
# @param message_body[String] the message to send
|
71
92
|
# @param kwargs_for_send[Hash] additional arguments for the submit (such as `delay_seconds`).
|
72
|
-
# Passes the arguments to the AWS SDK.
|
93
|
+
# Passes the arguments to the AWS SDK.
|
73
94
|
# @return [void]
|
74
95
|
def send_message(message_body, **kwargs_for_send)
|
75
96
|
send_multiple_messages {|via| via.send_message(message_body, **kwargs_for_send) }
|
@@ -189,11 +210,21 @@ class Sqewer::Connection
|
|
189
210
|
buffer.each_batch {|batch| handle_batch_with_retries(:delete_message_batch, batch) }
|
190
211
|
end
|
191
212
|
|
213
|
+
protected
|
214
|
+
|
215
|
+
def self.release_client
|
216
|
+
@client = nil
|
217
|
+
end
|
218
|
+
|
192
219
|
private
|
193
220
|
|
221
|
+
def network_and_aws_sdk_errors
|
222
|
+
[NotOurFaultAwsError, Seahorse::Client::NetworkingError, Aws::SQS::Errors::InternalError]
|
223
|
+
end
|
224
|
+
|
194
225
|
def handle_batch_with_retries(method, batch)
|
195
|
-
Retriable.retriable on:
|
196
|
-
resp = client.send(method, queue_url: @queue_url, entries: batch)
|
226
|
+
Retriable.retriable on: network_and_aws_sdk_errors, tries: MAX_RANDOM_FAILURES_PER_CALL do
|
227
|
+
resp = @client.send(method, queue_url: @queue_url, entries: batch)
|
197
228
|
wrong_messages, aws_failures = resp.failed.partition {|m| m.sender_fault }
|
198
229
|
if wrong_messages.any?
|
199
230
|
err = wrong_messages.inspect + ', ' + resp.inspect
|
@@ -204,12 +235,13 @@ class Sqewer::Connection
|
|
204
235
|
raise NotOurFaultAwsError
|
205
236
|
end
|
206
237
|
end
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
@client
|
211
|
-
|
212
|
-
|
213
|
-
|
238
|
+
rescue Aws::Errors::MissingCredentialsError
|
239
|
+
# We noticed cases where errors related to AWS credentials started to happen suddenly.
|
240
|
+
# We don't know the root cause yet, but what we can do is release the
|
241
|
+
# singleton @client instance because it contains a cache of credentials that in most
|
242
|
+
# cases is no longer valid.
|
243
|
+
self.class.release_client
|
244
|
+
|
245
|
+
raise
|
214
246
|
end
|
215
247
|
end
|
data/lib/sqewer/simple_job.rb
CHANGED
@@ -4,6 +4,13 @@
|
|
4
4
|
# * initialize() will have keyword access to all accessors, and will ensure you have called each one of them
|
5
5
|
# * to_h() will produce a symbolized Hash with all the properties defined using attr_accessor, and the job_class_name
|
6
6
|
# * inspect() will provide a sensible default string representation for logging
|
7
|
+
#
|
8
|
+
# This module validates if the attributes defined in the job class are the same as
|
9
|
+
# those persisted in the queue. More details on `Sqewer::SimpleJob#initialize`.
|
10
|
+
# Because of this, it's required to create a new job class when adding or removing
|
11
|
+
# an attribute.
|
12
|
+
# This mechanism guarantees strong consistency. Without it, a new deployed job class
|
13
|
+
# could process old incompatible payloads.
|
7
14
|
module Sqewer::SimpleJob
|
8
15
|
UnknownJobAttribute = Class.new(Sqewer::Error)
|
9
16
|
MissingAttribute = Class.new(Sqewer::Error)
|
@@ -53,7 +60,7 @@ module Sqewer::SimpleJob
|
|
53
60
|
accessor = "#{k}="
|
54
61
|
touched_attributes << k
|
55
62
|
unless respond_to?(accessor)
|
56
|
-
raise UnknownJobAttribute, "Unknown attribute #{k.inspect} for #{self.class}"
|
63
|
+
raise UnknownJobAttribute, "Unknown attribute #{k.inspect} for #{self.class}"
|
57
64
|
end
|
58
65
|
|
59
66
|
send("#{k}=", v)
|
data/lib/sqewer/version.rb
CHANGED
data/lib/sqewer/worker.rb
CHANGED
@@ -91,7 +91,7 @@ class Sqewer::Worker
|
|
91
91
|
|
92
92
|
consumers = (1..@num_threads).map do
|
93
93
|
Thread.new do
|
94
|
-
|
94
|
+
loop { take_and_execute }
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -233,8 +233,11 @@ class Sqewer::Worker
|
|
233
233
|
message = @execution_queue.pop(nonblock=true)
|
234
234
|
handle_message(message)
|
235
235
|
rescue ThreadError # Queue is empty
|
236
|
-
|
237
|
-
|
236
|
+
if stopping?
|
237
|
+
Thread.current.exit
|
238
|
+
else
|
239
|
+
sleep SLEEP_SECONDS_ON_EMPTY_QUEUE
|
240
|
+
end
|
238
241
|
rescue => e # anything else, at or below StandardError that does not need us to quit
|
239
242
|
@logger.error { '[worker] Failed "%s..." with %s: %s' % [message.inspect[0..64], e.class, e.message] }
|
240
243
|
e.backtrace.each { |s| @logger.debug{"\t#{s}"} }
|
data/sqewer.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = %q{Process jobs from SQS}
|
13
13
|
spec.description = %q{A full-featured library for all them SQS worker needs}
|
14
14
|
spec.homepage = "https://github.com/WeTransfer/sqewer"
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
15
16
|
|
16
17
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host"
|
17
18
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
@@ -49,4 +50,5 @@ Gem::Specification.new do |spec|
|
|
49
50
|
spec.add_development_dependency "dotenv"
|
50
51
|
spec.add_development_dependency "simplecov"
|
51
52
|
spec.add_development_dependency "appsignal", '~> 2'
|
53
|
+
spec.add_development_dependency "pry-byebug"
|
52
54
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqewer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 8.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-07-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk-sqs
|
@@ -221,11 +221,26 @@ dependencies:
|
|
221
221
|
- - "~>"
|
222
222
|
- !ruby/object:Gem::Version
|
223
223
|
version: '2'
|
224
|
+
- !ruby/object:Gem::Dependency
|
225
|
+
name: pry-byebug
|
226
|
+
requirement: !ruby/object:Gem::Requirement
|
227
|
+
requirements:
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: '0'
|
231
|
+
type: :development
|
232
|
+
prerelease: false
|
233
|
+
version_requirements: !ruby/object:Gem::Requirement
|
234
|
+
requirements:
|
235
|
+
- - ">="
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: '0'
|
224
238
|
description: A full-featured library for all them SQS worker needs
|
225
239
|
email:
|
226
240
|
- me@julik.nl
|
227
241
|
- linkyndy@gmail.com
|
228
242
|
executables:
|
243
|
+
- console
|
229
244
|
- sqewer
|
230
245
|
- sqewer_rails
|
231
246
|
extensions: []
|
@@ -239,10 +254,10 @@ files:
|
|
239
254
|
- Gemfile
|
240
255
|
- README.md
|
241
256
|
- Rakefile
|
257
|
+
- bin/console
|
242
258
|
- bin/sqewer
|
243
259
|
- bin/sqewer_rails
|
244
260
|
- example.env
|
245
|
-
- gemfiles/Gemfile.rails-4.2.x
|
246
261
|
- gemfiles/Gemfile.rails-5.0.x
|
247
262
|
- gemfiles/Gemfile.rails-5.1.x
|
248
263
|
- lib/sqewer.rb
|
@@ -278,14 +293,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
278
293
|
requirements:
|
279
294
|
- - ">="
|
280
295
|
- !ruby/object:Gem::Version
|
281
|
-
version:
|
296
|
+
version: 2.6.0
|
282
297
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
283
298
|
requirements:
|
284
299
|
- - ">="
|
285
300
|
- !ruby/object:Gem::Version
|
286
301
|
version: '0'
|
287
302
|
requirements: []
|
288
|
-
rubygems_version: 3.1.
|
303
|
+
rubygems_version: 3.1.6
|
289
304
|
signing_key:
|
290
305
|
specification_version: 4
|
291
306
|
summary: Process jobs from SQS
|