sqewer 6.4.1 → 8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|