soda-core 0.0.1 → 0.0.8
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/lib/soda.rb +37 -0
- data/lib/soda/cli.rb +51 -34
- data/lib/soda/client.rb +28 -11
- data/lib/soda/extensions/active_job.rb +27 -0
- data/lib/soda/fetcher.rb +1 -1
- data/lib/soda/middleware/chain.rb +1 -1
- data/lib/soda/processor.rb +27 -4
- data/lib/soda/rails.rb +6 -0
- data/lib/soda/retrier.rb +1 -1
- data/lib/soda/tools.rb +19 -0
- data/lib/soda/version.rb +1 -1
- data/lib/soda/worker.rb +7 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88762defaf2339fa04bbe565b9238d6edf1b6a3df2f68bd85c4bee62aa1e5397
|
4
|
+
data.tar.gz: b6b0934e5f9c7038859eed8dc28c8f6280223384e06f640c9ed907d8900f0392
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1ccfad1b68e0f0e63dfd92e625a76896693b77a5314ae557a486af21a31a6f7c48c46f8495a3e8d4d088687bacff85636016181b51a2dcd24c6c29395372e79
|
7
|
+
data.tar.gz: 22a7dc79c110eae266bb0b4323ec474e22cc38ef02dd79bf58c1f9c26233fe0c8a10ace9906ec7bd99e17b3cc00a9fc4e245f6bd103dc2c98bd9d3876e455432
|
data/lib/soda.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require "aws-sdk-sqs"
|
2
|
+
require "erb"
|
2
3
|
require "json"
|
3
4
|
require "logger"
|
4
5
|
require "securerandom"
|
5
6
|
require "set"
|
7
|
+
require "yaml"
|
6
8
|
|
7
9
|
require "soda/tools"
|
8
10
|
|
@@ -18,6 +20,7 @@ require "soda/retrier"
|
|
18
20
|
require "soda/worker"
|
19
21
|
|
20
22
|
module Soda
|
23
|
+
NAME = "Soda"
|
21
24
|
DEFAULTS = {
|
22
25
|
concurrency: 10,
|
23
26
|
}
|
@@ -64,6 +67,40 @@ module Soda
|
|
64
67
|
end
|
65
68
|
end
|
66
69
|
|
70
|
+
def queues=(configs)
|
71
|
+
queues do |registry|
|
72
|
+
names = []
|
73
|
+
configs.each do |cfg|
|
74
|
+
# Find or create the queue.
|
75
|
+
queue = registry.select(cfg.delete(:name))
|
76
|
+
|
77
|
+
# Update the attributes
|
78
|
+
name = queue.name
|
79
|
+
url = cfg.delete(:url) || queue.url
|
80
|
+
|
81
|
+
registry.register(
|
82
|
+
name,
|
83
|
+
url,
|
84
|
+
queue.options.merge(cfg),
|
85
|
+
)
|
86
|
+
|
87
|
+
names << queue.name
|
88
|
+
end
|
89
|
+
|
90
|
+
# For queues that are not included in the command, set their weight to
|
91
|
+
# zero so they can still be accessed.
|
92
|
+
registry.each do |queue|
|
93
|
+
unless names.include?(queue.name)
|
94
|
+
registry.register(
|
95
|
+
queue.name,
|
96
|
+
queue.url,
|
97
|
+
queue.options.merge(weight: 0),
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
67
104
|
def queue(name)
|
68
105
|
queues.select(name).tap do |queue|
|
69
106
|
yield(queue) if block_given?
|
data/lib/soda/cli.rb
CHANGED
@@ -12,6 +12,8 @@ module Soda
|
|
12
12
|
INT,
|
13
13
|
].freeze
|
14
14
|
|
15
|
+
DEFAULT_CONFIG = "config/soda.yml"
|
16
|
+
|
15
17
|
def self.start
|
16
18
|
new.run
|
17
19
|
end
|
@@ -23,6 +25,21 @@ module Soda
|
|
23
25
|
def run
|
24
26
|
build_options
|
25
27
|
|
28
|
+
logger.info("🥤 %s v%s" % [Soda::NAME, Soda::VERSION])
|
29
|
+
|
30
|
+
if rails?
|
31
|
+
if Rails::VERSION::MAJOR >= 5
|
32
|
+
require "./config/application.rb"
|
33
|
+
require "./config/environment.rb"
|
34
|
+
require "soda/rails"
|
35
|
+
require "soda/extensions/active_job"
|
36
|
+
|
37
|
+
logger.info("Loaded Rails v%s application." % ::Rails.version)
|
38
|
+
else
|
39
|
+
raise "Not compatible with Rails v%s!" % Rails.version
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
26
43
|
manager = Manager.new
|
27
44
|
manager.start
|
28
45
|
|
@@ -70,12 +87,20 @@ module Soda
|
|
70
87
|
parser = build_option_parser(opts)
|
71
88
|
parser.parse!(argv)
|
72
89
|
|
90
|
+
if File.exists?(default_config = File.expand_path(DEFAULT_CONFIG))
|
91
|
+
opts[:config] ||= default_config
|
92
|
+
end
|
93
|
+
|
94
|
+
if (file = opts.delete(:config_file))
|
95
|
+
parse_config_file(opts, opts.delete(:config))
|
96
|
+
end
|
97
|
+
|
73
98
|
if (req = opts.delete(:require))
|
74
99
|
require(req)
|
75
100
|
end
|
76
101
|
|
77
|
-
if (
|
78
|
-
|
102
|
+
if (queues = opts.delete(:queues))
|
103
|
+
Soda.queues = queues
|
79
104
|
end
|
80
105
|
|
81
106
|
options = Soda.options
|
@@ -88,46 +113,38 @@ module Soda
|
|
88
113
|
opts.merge!(require: val)
|
89
114
|
end
|
90
115
|
|
91
|
-
o.on("-q", "--
|
92
|
-
|
116
|
+
o.on("-q", "--queue QUEUE[,WEIGHT]", "Queue to listen to, with optional weights") do |val|
|
117
|
+
name, weight = val.split(/,/)
|
118
|
+
opts.merge!(queues: opts.fetch(:queues, []).push(name: name, weight: weight))
|
119
|
+
end
|
120
|
+
|
121
|
+
o.on("-c", "--concurrency [INT]", "Number of processor threads") do |val|
|
122
|
+
opts.merge!(concurrency: Integer(val))
|
93
123
|
end
|
94
124
|
end
|
95
125
|
end
|
96
126
|
|
97
|
-
def
|
98
|
-
|
99
|
-
opt.each do |name, weight|
|
100
|
-
# Find or create the queue.
|
101
|
-
queue = registry.select(name)
|
102
|
-
|
103
|
-
if weight
|
104
|
-
# Replace the queue with the same one, except mutate the options to
|
105
|
-
# include the specified weight.
|
106
|
-
registry.register(
|
107
|
-
queue.name,
|
108
|
-
queue.url,
|
109
|
-
queue.options.merge(weight: weight.to_i),
|
110
|
-
)
|
111
|
-
end
|
112
|
-
end
|
127
|
+
def parse_config_file(opts = {}, file)
|
128
|
+
path = File.expand_path(file)
|
113
129
|
|
114
|
-
|
115
|
-
|
116
|
-
names = opt.map(&:first)
|
117
|
-
registry.each do |queue|
|
118
|
-
unless names.include?(queue.name)
|
119
|
-
registry.register(
|
120
|
-
queue.name,
|
121
|
-
queue.url,
|
122
|
-
queue.options.merge(weight: 0),
|
123
|
-
)
|
124
|
-
end
|
125
|
-
end
|
130
|
+
unless File.exists?(path)
|
131
|
+
raise "File does not exist: %s"
|
126
132
|
end
|
133
|
+
|
134
|
+
opts.merge!(
|
135
|
+
deep_symbolize_keys(
|
136
|
+
YAML.load(
|
137
|
+
ERB.new(File.read(path)).result,
|
138
|
+
),
|
139
|
+
),
|
140
|
+
)
|
127
141
|
end
|
128
142
|
|
129
|
-
def
|
130
|
-
|
143
|
+
def rails?
|
144
|
+
require "rails"
|
145
|
+
defined?(::Rails)
|
146
|
+
rescue LoadError
|
147
|
+
false
|
131
148
|
end
|
132
149
|
end
|
133
150
|
end
|
data/lib/soda/client.rb
CHANGED
@@ -1,11 +1,27 @@
|
|
1
1
|
module Soda
|
2
2
|
class Client
|
3
|
+
DEFAULTS = {
|
4
|
+
"retry" => true,
|
5
|
+
"delay" => 0,
|
6
|
+
}
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def push(*args)
|
10
|
+
new.push(*args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def middleware
|
14
|
+
Soda.client_middleware
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
3
18
|
def push(item)
|
4
|
-
copy
|
5
|
-
mw = Soda.client_middleware
|
19
|
+
copy = normalize!(item)
|
6
20
|
|
7
|
-
|
8
|
-
|
21
|
+
self.class.middleware.use(item["klass"], copy, copy["queue"]) do
|
22
|
+
jid = copy["id"]
|
23
|
+
jid.tap do
|
24
|
+
queue = Soda.queue(copy["queue"])
|
9
25
|
queue.push_in(copy["delay"], Soda.dump_json(copy))
|
10
26
|
end
|
11
27
|
end
|
@@ -14,19 +30,20 @@ module Soda
|
|
14
30
|
private
|
15
31
|
|
16
32
|
def normalize!(item)
|
17
|
-
item
|
18
|
-
|
19
|
-
|
33
|
+
item = DEFAULTS.merge(item)
|
34
|
+
item.tap do
|
35
|
+
item.keys.each do |key|
|
36
|
+
item.merge!(String(key) => item.delete(key))
|
20
37
|
end
|
21
38
|
|
22
39
|
id = SecureRandom.base64(10)
|
23
|
-
klass =
|
24
|
-
delay =
|
25
|
-
queue =
|
40
|
+
klass = item["klass"].to_s
|
41
|
+
delay = item["delay"].to_i
|
42
|
+
queue = item["queue"] || Soda.default_queue!.name
|
26
43
|
|
27
44
|
# TODO: add validation
|
28
45
|
#
|
29
|
-
|
46
|
+
item.merge!(
|
30
47
|
"id" => id,
|
31
48
|
"klass" => klass,
|
32
49
|
"delay" => delay,
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveJob
|
2
|
+
module QueueAdapters
|
3
|
+
class SodaAdapter
|
4
|
+
def enqueue(job)
|
5
|
+
enqueue_at(job, Time.now)
|
6
|
+
end
|
7
|
+
|
8
|
+
def enqueue_at(job, ts)
|
9
|
+
job.provider_job_id = ::Soda::Client.push(
|
10
|
+
"klass" => JobWrapper,
|
11
|
+
"wrapped" => job.class,
|
12
|
+
"queue" => job.queue_name,
|
13
|
+
"delay" => [0, (ts - Time.now).to_i].max,
|
14
|
+
"args" => [job.serialize],
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
class JobWrapper
|
19
|
+
include ::Soda::Worker
|
20
|
+
|
21
|
+
def perform(data = {})
|
22
|
+
Base.execute(data.merge("provider_job_id" => id))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/soda/fetcher.rb
CHANGED
data/lib/soda/processor.rb
CHANGED
@@ -2,6 +2,12 @@ module Soda
|
|
2
2
|
class Processor
|
3
3
|
include Tools
|
4
4
|
|
5
|
+
class << self
|
6
|
+
def middleware
|
7
|
+
Soda.server_middleware
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
def initialize(manager)
|
6
12
|
@manager = manager
|
7
13
|
@retrier = Retrier.new
|
@@ -31,7 +37,7 @@ module Soda
|
|
31
37
|
|
32
38
|
def run
|
33
39
|
until stopped?
|
34
|
-
msgs = fetch
|
40
|
+
msgs = fetch || []
|
35
41
|
msgs.each(&method(:process))
|
36
42
|
end
|
37
43
|
rescue Exception => ex
|
@@ -50,7 +56,9 @@ module Soda
|
|
50
56
|
def process(msg)
|
51
57
|
if (job_hash = parse_job(msg.str))
|
52
58
|
job_logger.with(job_hash) do
|
53
|
-
|
59
|
+
reloader.wrap do
|
60
|
+
execute(job_hash, msg)
|
61
|
+
end
|
54
62
|
end
|
55
63
|
else
|
56
64
|
# We can't process the work because the JSON is invalid, so we have to
|
@@ -69,8 +77,7 @@ module Soda
|
|
69
77
|
worker = constantize(klass)
|
70
78
|
|
71
79
|
retrier.retry(job_hash, msg) do
|
72
|
-
middleware
|
73
|
-
middleware.use(worker, job_hash, queue.name, msg) do
|
80
|
+
self.class.middleware.use(worker, job_hash, queue.name, msg) do
|
74
81
|
instance = worker.new(job_hash)
|
75
82
|
instance.perform(*job_hash["args"])
|
76
83
|
end
|
@@ -98,5 +105,21 @@ module Soda
|
|
98
105
|
def constantize(str)
|
99
106
|
Object.const_get(str)
|
100
107
|
end
|
108
|
+
|
109
|
+
# To support Rails reloading from the CLI context, the following code find
|
110
|
+
# the Rails reloader or stubs a no-op one.
|
111
|
+
class StubReloader
|
112
|
+
def wrap; yield; end
|
113
|
+
end
|
114
|
+
|
115
|
+
def reloader
|
116
|
+
@reloader ||=
|
117
|
+
if defined?(::Soda::Rails)
|
118
|
+
application = ::Rails.application
|
119
|
+
application.reloader
|
120
|
+
else
|
121
|
+
StubReloader.new
|
122
|
+
end
|
123
|
+
end
|
101
124
|
end
|
102
125
|
end
|
data/lib/soda/rails.rb
ADDED
data/lib/soda/retrier.rb
CHANGED
data/lib/soda/tools.rb
CHANGED
@@ -19,5 +19,24 @@ module Soda
|
|
19
19
|
def now
|
20
20
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
21
21
|
end
|
22
|
+
|
23
|
+
def deep_symbolize_keys(hash)
|
24
|
+
transform_value = -> (value) {
|
25
|
+
case value
|
26
|
+
when Hash
|
27
|
+
deep_symbolize_keys(value)
|
28
|
+
when Array
|
29
|
+
value.map { |val| transform_value.call(val) }
|
30
|
+
else
|
31
|
+
value
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
{}.tap do |memo|
|
36
|
+
hash.each do |key, value|
|
37
|
+
memo.merge!(key.to_sym => transform_value.call(value))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
22
41
|
end
|
23
42
|
end
|
data/lib/soda/version.rb
CHANGED
data/lib/soda/worker.rb
CHANGED
@@ -28,6 +28,7 @@ module Soda
|
|
28
28
|
)
|
29
29
|
end
|
30
30
|
end
|
31
|
+
alias_method :perform_at, :perform_in
|
31
32
|
|
32
33
|
private
|
33
34
|
|
@@ -70,6 +71,12 @@ module Soda
|
|
70
71
|
@options = options
|
71
72
|
end
|
72
73
|
|
74
|
+
%i[id].each do |method|
|
75
|
+
define_method(method) do
|
76
|
+
options.fetch(String(method))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
73
80
|
private
|
74
81
|
|
75
82
|
attr_reader :options
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soda-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Portes Chaikin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-sqs
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- lib/soda.rb
|
64
64
|
- lib/soda/cli.rb
|
65
65
|
- lib/soda/client.rb
|
66
|
+
- lib/soda/extensions/active_job.rb
|
66
67
|
- lib/soda/fetcher.rb
|
67
68
|
- lib/soda/logger.rb
|
68
69
|
- lib/soda/manager.rb
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- lib/soda/processor.rb
|
71
72
|
- lib/soda/queue.rb
|
72
73
|
- lib/soda/queues/registry.rb
|
74
|
+
- lib/soda/rails.rb
|
73
75
|
- lib/soda/retrier.rb
|
74
76
|
- lib/soda/tools.rb
|
75
77
|
- lib/soda/version.rb
|