sqs_simplify 0.2.0
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 +7 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +383 -0
- data/README.pt-br.md +384 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/sqs_simplify/base.rb +212 -0
- data/lib/sqs_simplify/client.rb +34 -0
- data/lib/sqs_simplify/command.rb +89 -0
- data/lib/sqs_simplify/consumer.rb +154 -0
- data/lib/sqs_simplify/dead_queue.rb +65 -0
- data/lib/sqs_simplify/errors/execution_expired.rb +11 -0
- data/lib/sqs_simplify/errors/non_existent_queue.rb +11 -0
- data/lib/sqs_simplify/errors/reserved_method_name.rb +11 -0
- data/lib/sqs_simplify/execution_hook.rb +44 -0
- data/lib/sqs_simplify/faker_client.rb +78 -0
- data/lib/sqs_simplify/job.rb +193 -0
- data/lib/sqs_simplify/message.rb +24 -0
- data/lib/sqs_simplify/scheduler.rb +72 -0
- data/lib/sqs_simplify/version.rb +5 -0
- data/lib/sqs_simplify/worker.rb +99 -0
- data/lib/sqs_simplify.rb +68 -0
- data/rubocop.yml +3 -0
- data/sqs_simplify.gemspec +34 -0
- metadata +112 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SqsSimplify
|
|
4
|
+
class Scheduler < SqsSimplify::Base
|
|
5
|
+
include SqsSimplify::ExecutionHook
|
|
6
|
+
private_class_method :new
|
|
7
|
+
|
|
8
|
+
def initialize(message:, delay_seconds:, queue_url:, group_id: nil)
|
|
9
|
+
@message = message
|
|
10
|
+
@delay_seconds = delay_seconds
|
|
11
|
+
@queue_url = queue_url
|
|
12
|
+
@group_id = group_id
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def queue_url
|
|
18
|
+
self.class.queue_url
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_message
|
|
22
|
+
Message.new queue_url: @queue_url, body: dump_message(@message), delay_seconds: @delay_seconds,
|
|
23
|
+
group_id: @group_id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def send_message
|
|
27
|
+
sqs_message = build_message
|
|
28
|
+
self.class.call_hook :before_each, sqs_message
|
|
29
|
+
client.send_message(sqs_message.to_send).message_id
|
|
30
|
+
rescue Aws::SQS::Errors::NonExistentQueue => e
|
|
31
|
+
self.class.call_hook :resolver_exception, e, sqs_message
|
|
32
|
+
raise e
|
|
33
|
+
rescue StandardError => e
|
|
34
|
+
self.class.call_hook :resolver_exception, e, sqs_message
|
|
35
|
+
ensure
|
|
36
|
+
self.class.call_hook :after_each, sqs_message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class << self
|
|
40
|
+
def send_message(message:, after: nil, queue_url: nil, group_id: nil)
|
|
41
|
+
after = after.nil? ? 0 : after.to_i
|
|
42
|
+
raise 'parameter must be between 0 to 960 seconds' unless after >= 0 && after < 961
|
|
43
|
+
|
|
44
|
+
queue_url ||= self.queue_url
|
|
45
|
+
new(message: message, delay_seconds: after, queue_url: queue_url,
|
|
46
|
+
group_id: group_id).send :send_message
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def map_queue(nickname, &block)
|
|
50
|
+
const_name = nickname.capitalize
|
|
51
|
+
|
|
52
|
+
class_eval <<~M, __FILE__, __LINE__ + 1
|
|
53
|
+
class #{const_name} < #{self}; end
|
|
54
|
+
private_constant '#{const_name}'
|
|
55
|
+
|
|
56
|
+
def self.#{nickname}
|
|
57
|
+
#{const_name}
|
|
58
|
+
end
|
|
59
|
+
M
|
|
60
|
+
|
|
61
|
+
block&.call send(nickname)
|
|
62
|
+
mapped_queues[nickname] = const_get(const_name).name
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def mapped_queues
|
|
68
|
+
@mapped_queues ||= {}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SqsSimplify
|
|
4
|
+
class Worker
|
|
5
|
+
def initialize(**options, &callback)
|
|
6
|
+
self.queues = options[:queues]
|
|
7
|
+
self.priority = options[:priority]
|
|
8
|
+
self.worker_size = options[:worker_size]
|
|
9
|
+
self.parallel_type = options[:parallel_type]
|
|
10
|
+
self.callback = callback
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def perform
|
|
14
|
+
valid_queues!
|
|
15
|
+
|
|
16
|
+
if priority?
|
|
17
|
+
consumer_with_priority
|
|
18
|
+
else
|
|
19
|
+
consumer
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
attr_accessor :queues, :priority, :worker_size, :parallel_type, :callback
|
|
26
|
+
|
|
27
|
+
def sqs_consumers
|
|
28
|
+
@sqs_consumers ||= build_sqs_consumers
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_sqs_consumers
|
|
32
|
+
consumers = SqsSimplify.consumers
|
|
33
|
+
|
|
34
|
+
if queues
|
|
35
|
+
queues.map do |queue|
|
|
36
|
+
consumers.find { |consumer| consumer.queue_name == queue } || Struct.new(:queue_name).new
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
consumers
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def valid_queues!
|
|
44
|
+
if queues
|
|
45
|
+
check_option_queues!
|
|
46
|
+
else
|
|
47
|
+
check_has_any_consumer!
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def check_option_queues!
|
|
52
|
+
all_queue_names = sqs_consumers.map(&:queue_name)
|
|
53
|
+
|
|
54
|
+
invalid_queues = queues.reject do |queue|
|
|
55
|
+
all_queue_names.include? queue
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
raise "Option queue invalid: [#{invalid_queues.join(', ')}]" if invalid_queues.length.positive?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def check_has_any_consumer!
|
|
62
|
+
raise 'No queue consumers were found in this project' if sqs_consumers.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def priority?
|
|
66
|
+
priority
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def consumer_with_priority
|
|
70
|
+
accumulated = 0
|
|
71
|
+
index = 0
|
|
72
|
+
|
|
73
|
+
loop do
|
|
74
|
+
amount = execute(sqs_consumers[index])
|
|
75
|
+
if amount.positive?
|
|
76
|
+
accumulated += amount
|
|
77
|
+
index = 0
|
|
78
|
+
else
|
|
79
|
+
index += 1
|
|
80
|
+
return accumulated if index >= queues.count
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def consumer
|
|
86
|
+
number_of_executions = sqs_consumers.map do |sqs_consumer|
|
|
87
|
+
execute(sqs_consumer)
|
|
88
|
+
end
|
|
89
|
+
number_of_executions.reduce(&:+)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def execute(sqs_consumer)
|
|
93
|
+
options = { worker_size: worker_size, parallel_type: parallel_type }
|
|
94
|
+
result = sqs_consumer.consume_messages(**options)
|
|
95
|
+
callback&.call(result, sqs_consumer)
|
|
96
|
+
result
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/sqs_simplify.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'aws-sdk-sqs'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'logger'
|
|
7
|
+
require 'ostruct'
|
|
8
|
+
require 'parallel'
|
|
9
|
+
require 'pathname'
|
|
10
|
+
require 'timeout'
|
|
11
|
+
|
|
12
|
+
require 'sqs_simplify/execution_hook'
|
|
13
|
+
require 'sqs_simplify/client'
|
|
14
|
+
require 'sqs_simplify/base'
|
|
15
|
+
|
|
16
|
+
require 'sqs_simplify/command'
|
|
17
|
+
require 'sqs_simplify/consumer'
|
|
18
|
+
require 'sqs_simplify/faker_client'
|
|
19
|
+
|
|
20
|
+
require 'sqs_simplify/message'
|
|
21
|
+
require 'sqs_simplify/scheduler'
|
|
22
|
+
require 'sqs_simplify/version'
|
|
23
|
+
|
|
24
|
+
require 'sqs_simplify/worker'
|
|
25
|
+
require 'sqs_simplify/job'
|
|
26
|
+
require 'sqs_simplify/dead_queue'
|
|
27
|
+
|
|
28
|
+
require 'sqs_simplify/errors/execution_expired'
|
|
29
|
+
require 'sqs_simplify/errors/non_existent_queue'
|
|
30
|
+
require 'sqs_simplify/errors/reserved_method_name'
|
|
31
|
+
|
|
32
|
+
module SqsSimplify
|
|
33
|
+
include SqsSimplify::ExecutionHook
|
|
34
|
+
|
|
35
|
+
add_hook :message_not_deleted, :after_fork
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
def configure
|
|
39
|
+
block_given? ? yield(settings) : settings
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def settings
|
|
43
|
+
@settings ||= OpenStruct.new(
|
|
44
|
+
hooks: self,
|
|
45
|
+
worker: self::Worker,
|
|
46
|
+
root: Pathname.new(Dir.pwd)
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def consumers
|
|
51
|
+
@consumers ||= []
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def schedulers
|
|
55
|
+
@schedulers ||= []
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def logger
|
|
59
|
+
return @logger if @logger
|
|
60
|
+
|
|
61
|
+
path = settings.log_dir || "#{settings.root}/log"
|
|
62
|
+
FileUtils.mkdir_p(path) unless File.directory?(path)
|
|
63
|
+
@logger = Logger.new("#{path}/sqs_simplify.log")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class Error < StandardError; end
|
|
68
|
+
end
|
data/rubocop.yml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/sqs_simplify/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'sqs_simplify'
|
|
7
|
+
spec.version = SqsSimplify::VERSION
|
|
8
|
+
spec.authors = ['Ralph Baesso', 'Nathan Meira', 'Joathan Fontan']
|
|
9
|
+
spec.email = ['ralphsbaesso@gmail.com', 'nathanmeira1@gmail.com', 'joathan.fontan@brobotbr.com.br']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Simple producers, consumers and jobs on top of Amazon SQS'
|
|
12
|
+
spec.description = 'Send, consume and schedule Amazon SQS messages with jobs, consumers, ' \
|
|
13
|
+
'dead letter queues, FIFO group ids and a worker command.'
|
|
14
|
+
spec.homepage = 'https://github.com/joathan-fontan/sqs_simplify'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.0.0')
|
|
17
|
+
|
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
|
20
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
21
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
22
|
+
|
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
27
|
+
end
|
|
28
|
+
spec.bindir = 'exe'
|
|
29
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
30
|
+
spec.require_paths = ['lib']
|
|
31
|
+
|
|
32
|
+
spec.add_runtime_dependency 'aws-sdk-sqs', '~> 1.0'
|
|
33
|
+
spec.add_runtime_dependency 'parallel', '>= 1.20', '< 3'
|
|
34
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sqs_simplify
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ralph Baesso
|
|
8
|
+
- Nathan Meira
|
|
9
|
+
- Joathan Fontan
|
|
10
|
+
bindir: exe
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: aws-sdk-sqs
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - "~>"
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '1.0'
|
|
21
|
+
type: :runtime
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - "~>"
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '1.0'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: parallel
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '1.20'
|
|
35
|
+
- - "<"
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '3'
|
|
38
|
+
type: :runtime
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: '1.20'
|
|
45
|
+
- - "<"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3'
|
|
48
|
+
description: Send, consume and schedule Amazon SQS messages with jobs, consumers,
|
|
49
|
+
dead letter queues, FIFO group ids and a worker command.
|
|
50
|
+
email:
|
|
51
|
+
- ralphsbaesso@gmail.com
|
|
52
|
+
- nathanmeira1@gmail.com
|
|
53
|
+
- joathan.fontan@brobotbr.com.br
|
|
54
|
+
executables: []
|
|
55
|
+
extensions: []
|
|
56
|
+
extra_rdoc_files: []
|
|
57
|
+
files:
|
|
58
|
+
- ".gitignore"
|
|
59
|
+
- ".rspec"
|
|
60
|
+
- ".travis.yml"
|
|
61
|
+
- CHANGELOG.md
|
|
62
|
+
- Gemfile
|
|
63
|
+
- LICENSE.txt
|
|
64
|
+
- README.md
|
|
65
|
+
- README.pt-br.md
|
|
66
|
+
- Rakefile
|
|
67
|
+
- bin/console
|
|
68
|
+
- bin/setup
|
|
69
|
+
- lib/sqs_simplify.rb
|
|
70
|
+
- lib/sqs_simplify/base.rb
|
|
71
|
+
- lib/sqs_simplify/client.rb
|
|
72
|
+
- lib/sqs_simplify/command.rb
|
|
73
|
+
- lib/sqs_simplify/consumer.rb
|
|
74
|
+
- lib/sqs_simplify/dead_queue.rb
|
|
75
|
+
- lib/sqs_simplify/errors/execution_expired.rb
|
|
76
|
+
- lib/sqs_simplify/errors/non_existent_queue.rb
|
|
77
|
+
- lib/sqs_simplify/errors/reserved_method_name.rb
|
|
78
|
+
- lib/sqs_simplify/execution_hook.rb
|
|
79
|
+
- lib/sqs_simplify/faker_client.rb
|
|
80
|
+
- lib/sqs_simplify/job.rb
|
|
81
|
+
- lib/sqs_simplify/message.rb
|
|
82
|
+
- lib/sqs_simplify/scheduler.rb
|
|
83
|
+
- lib/sqs_simplify/version.rb
|
|
84
|
+
- lib/sqs_simplify/worker.rb
|
|
85
|
+
- rubocop.yml
|
|
86
|
+
- sqs_simplify.gemspec
|
|
87
|
+
homepage: https://github.com/joathan-fontan/sqs_simplify
|
|
88
|
+
licenses:
|
|
89
|
+
- MIT
|
|
90
|
+
metadata:
|
|
91
|
+
homepage_uri: https://github.com/joathan-fontan/sqs_simplify
|
|
92
|
+
source_code_uri: https://github.com/joathan-fontan/sqs_simplify
|
|
93
|
+
changelog_uri: https://github.com/joathan-fontan/sqs_simplify/blob/main/CHANGELOG.md
|
|
94
|
+
rubygems_mfa_required: 'true'
|
|
95
|
+
rdoc_options: []
|
|
96
|
+
require_paths:
|
|
97
|
+
- lib
|
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: 3.0.0
|
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
|
+
requirements:
|
|
105
|
+
- - ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: '0'
|
|
108
|
+
requirements: []
|
|
109
|
+
rubygems_version: 4.0.15
|
|
110
|
+
specification_version: 4
|
|
111
|
+
summary: Simple producers, consumers and jobs on top of Amazon SQS
|
|
112
|
+
test_files: []
|