cosmonats 0.1.1 → 0.1.2
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/cosmo/cli.rb +7 -3
- data/lib/cosmo/job/processor.rb +24 -19
- data/lib/cosmo/processor.rb +3 -4
- data/lib/cosmo/stream/processor.rb +20 -23
- data/lib/cosmo/stream.rb +2 -2
- data/lib/cosmo/version.rb +1 -1
- data/sig/cosmo/cli.rbs +1 -1
- data/sig/cosmo/job/processor.rbs +1 -1
- data/sig/cosmo/processor.rbs +2 -2
- data/sig/cosmo/stream/processor.rbs +5 -8
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: baa2c1820f8c3b420b3ef7411ad74bd8989f5a4d198df6bfe18b5596959d5464
|
|
4
|
+
data.tar.gz: 282eb6f3dcfc3945596426b3ba39e31cf68d84e73692d0bd92165485b69654ae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35c534343db619b2fe9bc314b9517bb67adb808b92c45ae64fc9fb8d3fa533d625d5e1e64149d7ff0ebf8158cd400188c9601ab8b9fe4622f34dbd73dd2a95fc
|
|
7
|
+
data.tar.gz: '08e9b894165cd0e6254fccca8d73c1cef88bde32e8345de21f812195573add70847c95a0a2cd4c87cb3afc90824028665de2a4a71118aa67c966c056c2680960'
|
data/lib/cosmo/cli.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Cosmo
|
|
|
15
15
|
|
|
16
16
|
def run
|
|
17
17
|
flags, command, options = parse
|
|
18
|
-
load_config(flags
|
|
18
|
+
load_config(flags)
|
|
19
19
|
puts self.class.banner
|
|
20
20
|
boot_application
|
|
21
21
|
require_path(flags[:require])
|
|
@@ -37,7 +37,8 @@ module Cosmo
|
|
|
37
37
|
[flags, command, options]
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def load_config(
|
|
40
|
+
def load_config(flags)
|
|
41
|
+
path = flags[:config_file]
|
|
41
42
|
raise ConfigNotFoundError, path if path && !File.exist?(path)
|
|
42
43
|
|
|
43
44
|
unless path
|
|
@@ -47,6 +48,8 @@ module Cosmo
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
Config.load(path)
|
|
51
|
+
Config.set(:concurrency, flags[:concurrency]) if flags[:concurrency]
|
|
52
|
+
Config.set(:timeout, flags[:timeout]) if flags[:timeout]
|
|
50
53
|
end
|
|
51
54
|
|
|
52
55
|
def boot_application
|
|
@@ -96,7 +99,8 @@ module Cosmo
|
|
|
96
99
|
end
|
|
97
100
|
|
|
98
101
|
o.on "-S", "--setup", "Load config, create streams and exit" do
|
|
99
|
-
load_config(flags
|
|
102
|
+
load_config(flags)
|
|
103
|
+
boot_application
|
|
100
104
|
|
|
101
105
|
Config[:streams].each do |name, config|
|
|
102
106
|
Client.instance.stream_info(name)
|
data/lib/cosmo/job/processor.rb
CHANGED
|
@@ -22,18 +22,23 @@ module Cosmo
|
|
|
22
22
|
subject = config.delete(:subject)
|
|
23
23
|
priority = config.delete(:priority)
|
|
24
24
|
@weights += ([stream_name] * priority.to_i) if priority
|
|
25
|
-
|
|
25
|
+
subscription = client.subscribe(subject, consumer_name, config)
|
|
26
|
+
@consumers << [subscription, stream_name]
|
|
26
27
|
end
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
def work_loop
|
|
30
|
+
def work_loop # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
|
|
30
31
|
while running?
|
|
31
32
|
@weights.shuffle.each do |stream_name|
|
|
32
33
|
break unless running?
|
|
33
34
|
|
|
34
35
|
begin
|
|
35
36
|
timeout = ENV.fetch("COSMO_JOBS_FETCH_TIMEOUT", 0.1).to_f
|
|
36
|
-
@pool.post
|
|
37
|
+
@pool.post do
|
|
38
|
+
subscription = @consumers.find { |(_, sn)| sn == stream_name }&.first
|
|
39
|
+
messages = fetch_messages(subscription, batch_size: 1, timeout:)
|
|
40
|
+
process(messages) if messages&.any?
|
|
41
|
+
end
|
|
37
42
|
rescue Concurrent::RejectedExecutionError
|
|
38
43
|
break # pool doesn't accept new jobs, we are shutting down
|
|
39
44
|
end
|
|
@@ -43,26 +48,26 @@ module Cosmo
|
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
def schedule_loop # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
51
|
+
def schedule_loop # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
|
|
47
52
|
while running?
|
|
48
53
|
break unless running?
|
|
49
54
|
|
|
55
|
+
now = Time.now.to_i
|
|
50
56
|
timeout = ENV.fetch("COSMO_JOBS_SCHEDULER_FETCH_TIMEOUT", 5).to_f
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
end
|
|
57
|
+
subscription = @consumers.find { |(_, sn)| sn == :scheduled }&.first
|
|
58
|
+
messages = fetch_messages(subscription, batch_size: 100, timeout:)
|
|
59
|
+
messages&.each do |message|
|
|
60
|
+
headers = message.header.except("X-Stream", "X-Subject", "X-Execute-At", "Nats-Expected-Stream")
|
|
61
|
+
stream, subject, execute_at = message.header.values_at("X-Stream", "X-Subject", "X-Execute-At")
|
|
62
|
+
headers["Nats-Expected-Stream"] = stream
|
|
63
|
+
execute_at = execute_at.to_i
|
|
64
|
+
|
|
65
|
+
if now >= execute_at
|
|
66
|
+
client.publish(subject, message.data, headers: headers)
|
|
67
|
+
message.ack
|
|
68
|
+
else
|
|
69
|
+
delay_ns = (execute_at - now) * 1_000_000_000
|
|
70
|
+
message.nak(delay: delay_ns)
|
|
66
71
|
end
|
|
67
72
|
end
|
|
68
73
|
|
data/lib/cosmo/processor.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Cosmo
|
|
|
10
10
|
@pool = pool
|
|
11
11
|
@running = running
|
|
12
12
|
@options = options
|
|
13
|
-
@consumers =
|
|
13
|
+
@consumers = []
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def run
|
|
@@ -39,9 +39,8 @@ module Cosmo
|
|
|
39
39
|
@running.true?
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def fetch_messages(
|
|
43
|
-
|
|
44
|
-
block_given? ? yield(messages) : process(stream_name, messages)
|
|
42
|
+
def fetch_messages(subscription, batch_size:, timeout:)
|
|
43
|
+
subscription.fetch(batch_size, timeout:)
|
|
45
44
|
rescue NATS::Timeout
|
|
46
45
|
# No messages, continue
|
|
47
46
|
end
|
|
@@ -5,8 +5,7 @@ module Cosmo
|
|
|
5
5
|
class Processor < ::Cosmo::Processor
|
|
6
6
|
def initialize(pool, running, options)
|
|
7
7
|
super
|
|
8
|
-
@configs =
|
|
9
|
-
@processors = {}
|
|
8
|
+
@configs = []
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
private
|
|
@@ -17,19 +16,20 @@ module Cosmo
|
|
|
17
16
|
|
|
18
17
|
def setup
|
|
19
18
|
setup_configs
|
|
20
|
-
setup_processors
|
|
21
19
|
setup_consumers
|
|
22
20
|
end
|
|
23
21
|
|
|
24
|
-
def work_loop
|
|
22
|
+
def work_loop # rubocop:disable Metrics/CyclomaticComplexity
|
|
25
23
|
while running?
|
|
26
|
-
@consumers.
|
|
24
|
+
@consumers.each do |(subscription, config, processor)|
|
|
27
25
|
break unless running?
|
|
28
26
|
|
|
29
27
|
begin
|
|
30
|
-
batch_size = @configs[stream_name][:batch_size]
|
|
31
28
|
timeout = ENV.fetch("COSMO_STREAMS_FETCH_TIMEOUT", 0.1).to_f
|
|
32
|
-
@pool.post
|
|
29
|
+
@pool.post do
|
|
30
|
+
messages = fetch_messages(subscription, batch_size: config[:batch_size], timeout:)
|
|
31
|
+
process(messages, processor) if messages&.any?
|
|
32
|
+
end
|
|
33
33
|
rescue Concurrent::RejectedExecutionError
|
|
34
34
|
break # pool doesn't accept new jobs, we are shutting down
|
|
35
35
|
end
|
|
@@ -39,9 +39,8 @@ module Cosmo
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def process(
|
|
42
|
+
def process(messages, processor) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
43
43
|
metadata = messages.last.metadata
|
|
44
|
-
processor = @processors[stream_name]
|
|
45
44
|
serializer = processor.class.default_options.dig(:publisher, :serializer)
|
|
46
45
|
messages = messages.map { Message.new(_1, serializer:) }
|
|
47
46
|
|
|
@@ -64,21 +63,21 @@ module Cosmo
|
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
def setup_configs
|
|
67
|
-
configs = static_config
|
|
68
|
-
|
|
69
|
-
@configs.merge!(configs)
|
|
70
|
-
end
|
|
66
|
+
@configs = static_config + dynamic_config
|
|
67
|
+
return unless @options[:processors]
|
|
71
68
|
|
|
72
|
-
|
|
73
|
-
@configs.
|
|
69
|
+
pattern = Regexp.new(@options[:processors].map { "\\b#{_1}\\b" }.join("|"))
|
|
70
|
+
@configs.select! { _1[:class].name.match?(pattern) }
|
|
74
71
|
end
|
|
75
72
|
|
|
76
73
|
def setup_consumers
|
|
77
|
-
@configs.each do |
|
|
74
|
+
@configs.each do |config|
|
|
75
|
+
processor = config[:class].new
|
|
78
76
|
subjects = config.dig(:consumer, :subjects)
|
|
79
77
|
deliver_policy = Config.deliver_policy(config[:start_position])
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
consumer_config, consumer_name = config.values_at(:consumer, :consumer_name)
|
|
79
|
+
subscription = client.subscribe(subjects, consumer_name, consumer_config.merge(deliver_policy))
|
|
80
|
+
@consumers << [subscription, config, processor]
|
|
82
81
|
end
|
|
83
82
|
end
|
|
84
83
|
|
|
@@ -86,14 +85,12 @@ module Cosmo
|
|
|
86
85
|
Config.dig(:consumers, :streams)&.filter_map do |config|
|
|
87
86
|
next unless (klass = Utils::String.safe_constantize(config[:class]))
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
end.
|
|
88
|
+
config.merge(class: klass)
|
|
89
|
+
end.to_a
|
|
91
90
|
end
|
|
92
91
|
|
|
93
92
|
def dynamic_config
|
|
94
|
-
Config.system[:streams].
|
|
95
|
-
[klass.default_options[:stream].to_sym, klass.default_options.merge(class: klass)]
|
|
96
|
-
end
|
|
93
|
+
Config.system[:streams].map { _1.default_options.merge(class: _1) }
|
|
97
94
|
end
|
|
98
95
|
end
|
|
99
96
|
end
|
data/lib/cosmo/stream.rb
CHANGED
|
@@ -9,12 +9,12 @@ module Cosmo
|
|
|
9
9
|
module Stream
|
|
10
10
|
def self.included(base)
|
|
11
11
|
base.extend(ClassMethods)
|
|
12
|
-
base.register
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
module ClassMethods
|
|
16
15
|
def options(stream: nil, consumer_name: nil, batch_size: nil, start_position: nil, consumer: nil, publisher: nil) # rubocop:disable Metrics/ParameterLists
|
|
17
|
-
|
|
16
|
+
register
|
|
17
|
+
default_options.merge!({ stream:, consumer_name:, batch_size:, start_position:, consumer:, publisher: }.compact)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def publish(data, subject: nil, **options)
|
data/lib/cosmo/version.rb
CHANGED
data/sig/cosmo/cli.rbs
CHANGED
data/sig/cosmo/job/processor.rbs
CHANGED
data/sig/cosmo/processor.rbs
CHANGED
|
@@ -2,7 +2,7 @@ module Cosmo
|
|
|
2
2
|
class Processor
|
|
3
3
|
@pool: Utils::ThreadPool
|
|
4
4
|
@running: untyped
|
|
5
|
-
@consumers:
|
|
5
|
+
@consumers: Array[untyped]
|
|
6
6
|
@options: Hash[Symbol, untyped]
|
|
7
7
|
|
|
8
8
|
def self.run: (*untyped) -> Processor
|
|
@@ -21,7 +21,7 @@ module Cosmo
|
|
|
21
21
|
|
|
22
22
|
def running?: () -> bool
|
|
23
23
|
|
|
24
|
-
def fetch_messages: (
|
|
24
|
+
def fetch_messages: (untyped subscription, batch_size: Integer, timeout: Float) ?{ (Array[untyped]) -> void } -> void
|
|
25
25
|
|
|
26
26
|
def client: () -> Client
|
|
27
27
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
module Cosmo
|
|
2
2
|
module Stream
|
|
3
3
|
class Processor < ::Cosmo::Processor
|
|
4
|
-
@configs:
|
|
5
|
-
@processors: Hash[Symbol, untyped]
|
|
4
|
+
@configs: Array[Hash[Symbol, untyped]]
|
|
6
5
|
|
|
7
|
-
def initialize: (Utils::ThreadPool pool, untyped running) -> void
|
|
6
|
+
def initialize: (Utils::ThreadPool pool, untyped running, Hash[Symbol, untyped] options) -> void
|
|
8
7
|
|
|
9
8
|
private
|
|
10
9
|
|
|
@@ -14,17 +13,15 @@ module Cosmo
|
|
|
14
13
|
|
|
15
14
|
def work_loop: () -> void
|
|
16
15
|
|
|
17
|
-
def process: (
|
|
16
|
+
def process: (Array[untyped] messages, untyped processor) -> void
|
|
18
17
|
|
|
19
18
|
def setup_configs: () -> void
|
|
20
19
|
|
|
21
|
-
def setup_processors: () -> void
|
|
22
|
-
|
|
23
20
|
def setup_consumers: () -> void
|
|
24
21
|
|
|
25
|
-
def static_config: -> Hash[Symbol, untyped]
|
|
22
|
+
def static_config: -> Array[Hash[Symbol, untyped]]
|
|
26
23
|
|
|
27
|
-
def dynamic_config: -> Hash[Symbol, untyped]
|
|
24
|
+
def dynamic_config: -> Array[Hash[Symbol, untyped]]
|
|
28
25
|
end
|
|
29
26
|
end
|
|
30
27
|
end
|