cosmonats 0.5.1 → 0.6.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 +4 -4
- data/README.md +1 -1
- data/lib/cosmo/client.rb +36 -1
- data/lib/cosmo/logger.rb +21 -3
- data/lib/cosmo/processor.rb +7 -12
- data/lib/cosmo/utils/overrides.rb +185 -0
- data/lib/cosmo/version.rb +1 -1
- data/sig/cosmo/client.rbs +5 -1
- data/sig/cosmo/logger.rbs +10 -0
- data/sig/cosmo/processor.rbs +0 -3
- 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: 1b9d8091f782c96278e0de951486f14f3207f8af37d99f5460d122ee61ab0616
|
|
4
|
+
data.tar.gz: 0e76adacb61e924afd50d127a0c5259c9c454827e75276b44fba0ba7879409a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0277a84383b59f6c5fe7502a94f51619778aef691877dad39cf093733fbc69b8a2f4ac676006f4e67bf60db84af03ab49b741d38662652ce4fb017e1aef5f699
|
|
7
|
+
data.tar.gz: 2c850062acd3f24925e0136ef95ff7ea8c24a279f9ae7ad04526baea01524e46dcd266e8cc996d918a091fc39335d8283000dab56daffc46758e60ef17ea460b
|
data/README.md
CHANGED
data/lib/cosmo/client.rb
CHANGED
|
@@ -22,8 +22,13 @@ module Cosmo
|
|
|
22
22
|
js.publish(subject, payload, **params)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
# Create a pull subscription. Durable with +consumer_name+, and ephemeral without.
|
|
26
|
+
# @param config [Hash] Consumer config. Ephemeral consumers additionally require
|
|
27
|
+
# +:stream+ and +:inactive_threshold+ (seconds the consumer survives without a fetch).
|
|
25
28
|
def subscribe(subject, consumer_name, config)
|
|
26
|
-
js.pull_subscribe(subject, consumer_name, config: config)
|
|
29
|
+
return js.pull_subscribe(subject, consumer_name, config: config) if consumer_name
|
|
30
|
+
|
|
31
|
+
ephemeral_subscribe(subject, config)
|
|
27
32
|
end
|
|
28
33
|
|
|
29
34
|
def stream_info(name)
|
|
@@ -103,6 +108,10 @@ module Cosmo
|
|
|
103
108
|
js.consumer_info(stream_name, consumer_name)
|
|
104
109
|
end
|
|
105
110
|
|
|
111
|
+
def delete_consumer(stream_name, consumer_name)
|
|
112
|
+
js.delete_consumer(stream_name, consumer_name)
|
|
113
|
+
end
|
|
114
|
+
|
|
106
115
|
def get_message(stream_name, **options)
|
|
107
116
|
js.get_msg(stream_name, **options)
|
|
108
117
|
end
|
|
@@ -133,6 +142,32 @@ module Cosmo
|
|
|
133
142
|
|
|
134
143
|
private
|
|
135
144
|
|
|
145
|
+
# NOTE: nats-pure's #pull_subscribe has no path to a true ephemeral pull consumer.
|
|
146
|
+
# Its rescue branch unconditionally sets `config[:durable_name] = durable` (jetstream.rb).
|
|
147
|
+
def ephemeral_subscribe(subject, config) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
148
|
+
config = config.dup
|
|
149
|
+
stream = config.delete(:stream) or raise ArgumentError, "stream required for ephemeral consumers"
|
|
150
|
+
raise ArgumentError, "inactive_threshold required for ephemeral consumers" unless config[:inactive_threshold]
|
|
151
|
+
|
|
152
|
+
subject = subject.first if subject.is_a?(Array) && subject.size == 1
|
|
153
|
+
consumer_config = NATS::JetStream::API::ConsumerConfig.new(config)
|
|
154
|
+
if subject.is_a?(Array)
|
|
155
|
+
consumer_config[:filter_subjects] ||= subject
|
|
156
|
+
else
|
|
157
|
+
consumer_config[:filter_subject] ||= subject
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
info = js.add_consumer(stream, consumer_config)
|
|
161
|
+
|
|
162
|
+
sub = nc.subscribe(nc.new_inbox)
|
|
163
|
+
sub.extend(NATS::JetStream.const_get(:PullSubscription))
|
|
164
|
+
sub.jsi = NATS::JetStream.const_get(:JS)::Sub.new(
|
|
165
|
+
js: js, stream: stream, consumer: info.name,
|
|
166
|
+
nms: "#{js.prefix}.CONSUMER.MSG.NEXT.#{stream}.#{info.name}"
|
|
167
|
+
)
|
|
168
|
+
sub
|
|
169
|
+
end
|
|
170
|
+
|
|
136
171
|
# NOTE: KV manager in nats-pure hardcodes the fields it copies into StreamConfig,
|
|
137
172
|
# so `allow_msg_ttl` is never forwarded via create_key_value. Send the raw stream-create API request instead.
|
|
138
173
|
def create_kv_with_msg_ttl(name, **options)
|
data/lib/cosmo/logger.rb
CHANGED
|
@@ -5,6 +5,8 @@ require "forwardable"
|
|
|
5
5
|
|
|
6
6
|
module Cosmo
|
|
7
7
|
module Logger
|
|
8
|
+
TRACE = -1 # Below DEBUG; opt in with COSMO_LOG_LEVEL=trace for high-frequency polling/loop noise
|
|
9
|
+
|
|
8
10
|
module Context
|
|
9
11
|
KEY = :cosmo_context
|
|
10
12
|
|
|
@@ -45,10 +47,21 @@ module Cosmo
|
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
|
|
50
|
+
# Adds TRACE (below DEBUG) on top of stdlib's fixed DEBUG..UNKNOWN severities.
|
|
51
|
+
class Instance < ::Logger
|
|
52
|
+
def trace(progname = nil, &)
|
|
53
|
+
add(TRACE, nil, progname, &)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def format_severity(severity)
|
|
57
|
+
severity == TRACE ? "TRACE" : super
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
48
61
|
class << self
|
|
49
62
|
extend Forwardable
|
|
50
63
|
|
|
51
|
-
delegate %i[info error debug warn fatal] => :instance
|
|
64
|
+
delegate %i[info error debug warn fatal trace] => :instance
|
|
52
65
|
end
|
|
53
66
|
|
|
54
67
|
def self.with(...)
|
|
@@ -60,12 +73,17 @@ module Cosmo
|
|
|
60
73
|
end
|
|
61
74
|
|
|
62
75
|
def self.instance
|
|
63
|
-
@instance ||=
|
|
76
|
+
@instance ||= Instance.new($stdout).tap do |logger|
|
|
64
77
|
logger.formatter = SimpleFormatter.new
|
|
65
|
-
logger.level =
|
|
78
|
+
logger.level = coerce_level(ENV.fetch("COSMO_LOG_LEVEL", "info"))
|
|
66
79
|
end
|
|
67
80
|
end
|
|
68
81
|
|
|
82
|
+
def self.coerce_level(level)
|
|
83
|
+
level.to_s.downcase == "trace" ? TRACE : ::Logger::Severity.coerce(level)
|
|
84
|
+
end
|
|
85
|
+
private_class_method :coerce_level
|
|
86
|
+
|
|
69
87
|
def self.instance=(logger)
|
|
70
88
|
@instance = logger
|
|
71
89
|
end
|
data/lib/cosmo/processor.rb
CHANGED
|
@@ -60,14 +60,14 @@ module Cosmo
|
|
|
60
60
|
stream_name = config[:stream].to_s
|
|
61
61
|
ttl = Utils::Duration.parse(ENV.fetch("COSMO_STREAM_PAUSED_RECHECK_TTL", STREAM_PAUSED_RECHECK_TTL))
|
|
62
62
|
if @cache.fetch("#{stream_name}:paused", ttl:) { API::Stream.new(stream_name).paused? }
|
|
63
|
-
Logger.
|
|
63
|
+
Logger.trace "stream #{stream_name} is paused, skipping fetch"
|
|
64
64
|
next
|
|
65
65
|
end
|
|
66
66
|
all_paused = false
|
|
67
67
|
|
|
68
68
|
_, skip_t = consumer_state[stream_name]
|
|
69
69
|
if skip_t && Time.now < skip_t
|
|
70
|
-
Logger.
|
|
70
|
+
Logger.trace "stream #{stream_name} is empty, backing off"
|
|
71
71
|
next
|
|
72
72
|
end
|
|
73
73
|
all_empty = false
|
|
@@ -79,9 +79,9 @@ module Cosmo
|
|
|
79
79
|
next if skip_t && Time.now < skip_t
|
|
80
80
|
|
|
81
81
|
timeout = fetch_timeout(config)
|
|
82
|
-
Logger.
|
|
83
|
-
messages =
|
|
84
|
-
Logger.
|
|
82
|
+
Logger.trace "fetching #{fetch_subjects(config).inspect}, timeout=#{timeout}"
|
|
83
|
+
messages = fetch(subscription, batch_size: config[:batch_size], timeout:)
|
|
84
|
+
Logger.trace "fetched (#{messages&.size.to_i}) messages"
|
|
85
85
|
if messages&.any?
|
|
86
86
|
consumer_state.delete(stream_name)
|
|
87
87
|
process(messages, processor)
|
|
@@ -104,14 +104,14 @@ module Cosmo
|
|
|
104
104
|
|
|
105
105
|
if all_paused
|
|
106
106
|
period = Utils::Duration.parse(ENV.fetch("COSMO_STREAMS_PAUSED_IDLE_SLEEP", STREAMS_PAUSED_IDLE_SLEEP))
|
|
107
|
-
Logger.
|
|
107
|
+
Logger.trace "all streams paused, sleep=#{period}"
|
|
108
108
|
sleep(period)
|
|
109
109
|
elsif all_empty
|
|
110
110
|
next_wake = consumer_state.values.filter_map { |_, t| t }.min
|
|
111
111
|
next unless next_wake # entry was deleted concurrently (messages arrived), re-loop immediately
|
|
112
112
|
|
|
113
113
|
remaining = [next_wake - Time.now, 0.01].max
|
|
114
|
-
Logger.
|
|
114
|
+
Logger.trace "all streams empty, sleep=#{remaining}"
|
|
115
115
|
sleep(remaining)
|
|
116
116
|
end
|
|
117
117
|
end
|
|
@@ -158,11 +158,6 @@ module Cosmo
|
|
|
158
158
|
Utils::Stopwatch.new
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
-
def lock(stream_name, &)
|
|
162
|
-
@locks ||= Hash.new { |h, k| h[k] = Mutex.new }
|
|
163
|
-
@locks[stream_name].synchronize(&)
|
|
164
|
-
end
|
|
165
|
-
|
|
166
161
|
def consumer_state
|
|
167
162
|
@consumer_state ||= Concurrent::Map.new
|
|
168
163
|
end
|
|
@@ -13,3 +13,188 @@ Cosmo::Utils::Warnings.silence do
|
|
|
13
13
|
members = NATS::JetStream::PubAck.members + [:val]
|
|
14
14
|
NATS::JetStream::PubAck = Struct.new(*members, keyword_init: true)
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
# Upstream bug in nats-pure 2.5.0 (https://github.com/nats-io/nats.rb):
|
|
18
|
+
# NATS::JetStream::PullSubscription#fetch only assigns its `start_time` local in the
|
|
19
|
+
# `batch > 1` branch, but the final "did we time out" check outside the case statement
|
|
20
|
+
# reads it unconditionally. For `batch == 1` (what Cosmo::Processor always uses),
|
|
21
|
+
# `start_time` is nil there -- normally masked because the `batch == 1` branch has its
|
|
22
|
+
# own timeout check (using a properly-set `t`) that raises first.
|
|
23
|
+
#
|
|
24
|
+
# It only surfaces once two threads call #fetch concurrently on the *same* subscription:
|
|
25
|
+
# @pending_queue/wait_for_msgs_cond are shared per-subscription state, and #dispatch's
|
|
26
|
+
# `wait_for_msgs_cond.signal` wakes exactly one arbitrary waiter -- not necessarily the
|
|
27
|
+
# one whose own request produced that wakeup. A thread woken by someone else's signal
|
|
28
|
+
# finds nothing left in the (already-drained) queue, so it skips its own inner timeout
|
|
29
|
+
# check and falls into the buggy tail check, raising `TypeError: nil can't be coerced
|
|
30
|
+
# into Float` instead of the intended timeout/empty result. Reproduced deterministically
|
|
31
|
+
# with N threads fetching in a loop against the same PullSubscription.
|
|
32
|
+
#
|
|
33
|
+
# Second, separate upstream bug in the same method: the post-wait timeout check below
|
|
34
|
+
# (`raise ... if MonotonicTime.since(t) > timeout`) fires unconditionally, unlike every
|
|
35
|
+
# other timeout check in this method (all guarded with `msgs.empty? &&`). If the unsynchronized
|
|
36
|
+
# pop just above it succeeded in grabbing a real, already-delivered message -- which can happen
|
|
37
|
+
# even after `timeout` has technically elapsed, since #dispatch's signal and this thread actually
|
|
38
|
+
# resuming are two different moments -- that message is already gone from @pending_queue with
|
|
39
|
+
# nowhere else to go, yet gets discarded here and a plain NATS::Timeout raised instead. Callers
|
|
40
|
+
# (including Cosmo::Processor#fetch) treat NATS::Timeout as "no messages", so the message is lost
|
|
41
|
+
# silently: never processed, never acked, and not redelivered until the consumer's ack_wait expires.
|
|
42
|
+
# Reproduces reliably with several threads fetching (batch: 1) concurrently against the same
|
|
43
|
+
# subscription, e.g. Cosmo::Job::Processor's thread pool.
|
|
44
|
+
#
|
|
45
|
+
# Vendored copy of nats-pure's PullSubscription#fetch, kept as close to
|
|
46
|
+
# upstream as possible (two one-line fixes, see comments above), so it's easy to diff against the
|
|
47
|
+
# next nats-pure release and drop once fixed there.
|
|
48
|
+
|
|
49
|
+
# rubocop:disable all
|
|
50
|
+
module NATS
|
|
51
|
+
class JetStream
|
|
52
|
+
module PullSubscription
|
|
53
|
+
def fetch(batch = 1, params = {})
|
|
54
|
+
raise ::NATS::JetStream::Error.new("nats: invalid batch size") if batch < 1
|
|
55
|
+
|
|
56
|
+
t = MonotonicTime.now
|
|
57
|
+
start_time = t # fixes the upstream bug -- see comment above
|
|
58
|
+
timeout = params[:timeout] ||= 5
|
|
59
|
+
expires = (timeout * 1_000_000_000) - 100_000
|
|
60
|
+
next_req = { batch: batch }
|
|
61
|
+
|
|
62
|
+
msgs = []
|
|
63
|
+
case
|
|
64
|
+
when batch == 1
|
|
65
|
+
synchronize do
|
|
66
|
+
unless @pending_queue.empty?
|
|
67
|
+
msg = @pending_queue.pop
|
|
68
|
+
@pending_size -= msg.data.size
|
|
69
|
+
if JS.is_status_msg(msg)
|
|
70
|
+
case msg.header["Status"]
|
|
71
|
+
when JS::Status::NoMsgs then nil
|
|
72
|
+
when JS::Status::RequestTimeout then nil # Skip
|
|
73
|
+
else raise JS.from_msg(msg)
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
msgs << msg
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
next_req[:expires] = expires
|
|
82
|
+
if msgs.empty?
|
|
83
|
+
@nc.publish(@jsi.nms, JS.next_req_to_json(next_req), @subject)
|
|
84
|
+
synchronize { wait_for_msgs_cond.wait(timeout) }
|
|
85
|
+
|
|
86
|
+
unless @pending_queue.empty?
|
|
87
|
+
msg = @pending_queue.pop
|
|
88
|
+
@pending_size -= msg.data.size
|
|
89
|
+
msgs << msg
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
raise ::NATS::Timeout.new("nats: fetch timeout") if msgs.empty? && (MonotonicTime.since(t) > timeout)
|
|
93
|
+
|
|
94
|
+
if JS.is_status_msg(msgs.first)
|
|
95
|
+
msg = msgs.first
|
|
96
|
+
case msg.header[JS::Header::Status]
|
|
97
|
+
when JS::Status::RequestTimeout then raise NATS::Timeout.new("nats: fetch request timeout")
|
|
98
|
+
else raise JS.from_msg(msgs.first)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
when batch > 1
|
|
103
|
+
synchronize do
|
|
104
|
+
if batch <= @pending_queue.size
|
|
105
|
+
batch.times do
|
|
106
|
+
msg = @pending_queue.pop
|
|
107
|
+
@pending_size -= msg.data.size
|
|
108
|
+
if JS.is_status_msg(msg)
|
|
109
|
+
case msg.header[JS::Header::Status]
|
|
110
|
+
when JS::Status::NoMsgs, JS::Status::RequestTimeout then next
|
|
111
|
+
else raise JS.from_msg(msg)
|
|
112
|
+
end
|
|
113
|
+
else
|
|
114
|
+
msgs << msg
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
return msgs
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
next_req[:no_wait] = true
|
|
122
|
+
@nc.publish(@jsi.nms, JS.next_req_to_json(next_req), @subject)
|
|
123
|
+
|
|
124
|
+
start_time = MonotonicTime.now
|
|
125
|
+
msg = nil
|
|
126
|
+
|
|
127
|
+
synchronize do
|
|
128
|
+
wait_for_msgs_cond.wait(timeout)
|
|
129
|
+
unless @pending_queue.empty?
|
|
130
|
+
msg = @pending_queue.pop
|
|
131
|
+
@pending_size -= msg.data.size
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if !msg.nil? && JS.is_status_msg(msg)
|
|
136
|
+
case msg.header[JS::Header::Status]
|
|
137
|
+
when JS::Status::NoMsgs
|
|
138
|
+
next_req[:expires] = expires
|
|
139
|
+
next_req.delete(:no_wait)
|
|
140
|
+
@nc.publish(@jsi.nms, JS.next_req_to_json(next_req), @subject)
|
|
141
|
+
when JS::Status::RequestTimeout
|
|
142
|
+
raise NATS::Timeout.new("nats: fetch request timeout")
|
|
143
|
+
else
|
|
144
|
+
raise JS.from_msg(msg)
|
|
145
|
+
end
|
|
146
|
+
else
|
|
147
|
+
msgs << msg unless msg.nil?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
duration = MonotonicTime.since(start_time)
|
|
151
|
+
raise NATS::Timeout.new("nats: fetch timeout") if msgs.empty? && (duration > timeout)
|
|
152
|
+
|
|
153
|
+
needed = batch - msgs.count
|
|
154
|
+
while (needed > 0) && (MonotonicTime.since(start_time) < timeout)
|
|
155
|
+
duration = MonotonicTime.since(start_time)
|
|
156
|
+
|
|
157
|
+
synchronize do
|
|
158
|
+
if @pending_queue.empty?
|
|
159
|
+
deadline = timeout - duration
|
|
160
|
+
wait_for_msgs_cond.wait(deadline) if deadline > 0
|
|
161
|
+
|
|
162
|
+
duration = MonotonicTime.since(start_time)
|
|
163
|
+
if msgs.empty? && @pending_queue.empty? && (duration > timeout)
|
|
164
|
+
raise NATS::Timeout.new("nats: fetch timeout")
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
unless @pending_queue.empty?
|
|
169
|
+
msg = @pending_queue.pop
|
|
170
|
+
@pending_size -= msg.data.size
|
|
171
|
+
|
|
172
|
+
if JS.is_status_msg(msg)
|
|
173
|
+
case msg.header[JS::Header::Status]
|
|
174
|
+
when JS::Status::NoMsgs, JS::Status::RequestTimeout
|
|
175
|
+
duration = MonotonicTime.since(start_time)
|
|
176
|
+
if duration > timeout
|
|
177
|
+
raise NATS::Timeout.new("nats: fetch timeout") if msgs.empty?
|
|
178
|
+
|
|
179
|
+
return msgs
|
|
180
|
+
end
|
|
181
|
+
else
|
|
182
|
+
raise JS.from_msg(msg)
|
|
183
|
+
end
|
|
184
|
+
else
|
|
185
|
+
msgs << msg
|
|
186
|
+
needed -= 1
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
raise ::NATS::Timeout.new("nats: fetch timeout") if msgs.empty? && (MonotonicTime.since(start_time) > timeout)
|
|
194
|
+
|
|
195
|
+
msgs
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
# rubocop:enable all
|
data/lib/cosmo/version.rb
CHANGED
data/sig/cosmo/client.rbs
CHANGED
|
@@ -13,7 +13,7 @@ module Cosmo
|
|
|
13
13
|
|
|
14
14
|
def publish: (::String subject, ::String payload, **untyped params) -> untyped
|
|
15
15
|
|
|
16
|
-
def subscribe: (::String | Array[::String] subject, ::String consumer_name, Hash[Symbol, untyped] config) -> untyped
|
|
16
|
+
def subscribe: (::String | Array[::String] subject, ::String? consumer_name, Hash[Symbol, untyped] config) -> untyped
|
|
17
17
|
|
|
18
18
|
def stream_info: (::String | Symbol name) -> untyped
|
|
19
19
|
|
|
@@ -39,6 +39,8 @@ module Cosmo
|
|
|
39
39
|
|
|
40
40
|
def consumer_info: (::String stream_name, ::String consumer_name) -> NATS::JetStream::API::ConsumerInfo
|
|
41
41
|
|
|
42
|
+
def delete_consumer: (::String stream_name, ::String consumer_name) -> bool
|
|
43
|
+
|
|
42
44
|
def get_message: (::String | Symbol name, **untyped options) -> NATS::JetStream::API::RawStreamMsg
|
|
43
45
|
|
|
44
46
|
def delete_message: (::String name, ::Integer seq) -> Hash[::String, untyped]
|
|
@@ -51,6 +53,8 @@ module Cosmo
|
|
|
51
53
|
|
|
52
54
|
private
|
|
53
55
|
|
|
56
|
+
def ephemeral_subscribe: (::String | Array[::String] subject, Hash[Symbol, untyped] config) -> untyped
|
|
57
|
+
|
|
54
58
|
def create_kv_with_msg_ttl: (::String name, **untyped opts) -> untyped
|
|
55
59
|
end
|
|
56
60
|
end
|
data/sig/cosmo/logger.rbs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Cosmo
|
|
2
2
|
module Logger
|
|
3
|
+
TRACE: Integer
|
|
4
|
+
|
|
3
5
|
module Context
|
|
4
6
|
KEY: Symbol
|
|
5
7
|
|
|
@@ -20,6 +22,12 @@ module Cosmo
|
|
|
20
22
|
def call: (::String severity, Time time, untyped _, ::String msg) -> ::String
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
class Instance < ::Logger
|
|
26
|
+
def trace: (?::String? progname) ?{ () -> ::String } -> true
|
|
27
|
+
|
|
28
|
+
def format_severity: (Integer severity) -> ::String
|
|
29
|
+
end
|
|
30
|
+
|
|
23
31
|
def self.info: (::String) -> void
|
|
24
32
|
|
|
25
33
|
def self.error: (::String | Exception) -> void
|
|
@@ -30,6 +38,8 @@ module Cosmo
|
|
|
30
38
|
|
|
31
39
|
def self.fatal: (::String) -> void
|
|
32
40
|
|
|
41
|
+
def self.trace: (::String | Exception) -> void
|
|
42
|
+
|
|
33
43
|
def self.with: (**untyped) ?{ () -> void } -> void
|
|
34
44
|
|
|
35
45
|
def self.without: (*Symbol) -> nil
|
data/sig/cosmo/processor.rbs
CHANGED
|
@@ -10,7 +10,6 @@ module Cosmo
|
|
|
10
10
|
@threads: Array[Thread]
|
|
11
11
|
@cache: Utils::TTLCache
|
|
12
12
|
@options: Hash[Symbol, untyped]
|
|
13
|
-
@locks: Hash[::String, Mutex]
|
|
14
13
|
@consumer_state: untyped
|
|
15
14
|
|
|
16
15
|
def self.run: (*untyped) -> Processor
|
|
@@ -49,8 +48,6 @@ module Cosmo
|
|
|
49
48
|
|
|
50
49
|
def stopwatch: () -> Utils::Stopwatch
|
|
51
50
|
|
|
52
|
-
def lock: (::String stream_name) { () -> void } -> void
|
|
53
|
-
|
|
54
51
|
def consumer_state: () -> untyped
|
|
55
52
|
end
|
|
56
53
|
end
|