julewire-core 1.0.1 → 1.1.1
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/CHANGELOG.md +22 -0
- data/docs/configuration.md +14 -7
- data/docs/context-and-propagation.md +20 -0
- data/docs/contracts.md +23 -49
- data/docs/extensions-and-api.md +78 -82
- data/docs/health-schema.md +12 -2
- data/docs/internals.md +21 -20
- data/docs/outputs-and-lifecycle.md +10 -6
- data/docs/records-and-data-policy.md +36 -5
- data/lib/julewire/core/cli/doctor.rb +20 -16
- data/lib/julewire/core/cli/line_helpers.rb +23 -12
- data/lib/julewire/core/cli/log_formats/core_json_decoder.rb +3 -3
- data/lib/julewire/core/cli/log_formats.rb +9 -9
- data/lib/julewire/core/cli/tail.rb +19 -14
- data/lib/julewire/core/cli/transcode.rb +4 -5
- data/lib/julewire/core/cli.rb +1 -1
- data/lib/julewire/core/configuration.rb +1 -1
- data/lib/julewire/core/context_store.rb +51 -87
- data/lib/julewire/core/destinations/chaos_output.rb +2 -2
- data/lib/julewire/core/destinations/collection.rb +8 -16
- data/lib/julewire/core/destinations/definition.rb +1 -9
- data/lib/julewire/core/destinations/destination.rb +13 -63
- data/lib/julewire/core/destinations/processor_handling.rb +78 -0
- data/lib/julewire/core/destinations/registry.rb +1 -1
- data/lib/julewire/core/destinations/sink.rb +0 -1
- data/lib/julewire/core/destinations/synchronized_output.rb +14 -13
- data/lib/julewire/core/destinations/tail_sampling.rb +18 -27
- data/lib/julewire/core/destinations/write_step.rb +5 -5
- data/lib/julewire/core/destinations.rb +0 -7
- data/lib/julewire/core/diagnostics/callback_notifier.rb +4 -2
- data/lib/julewire/core/diagnostics/doctor.rb +16 -9
- data/lib/julewire/core/diagnostics/failure_snapshot.rb +6 -2
- data/lib/julewire/core/diagnostics/health.rb +41 -57
- data/lib/julewire/core/diagnostics/integration_health_store.rb +11 -24
- data/lib/julewire/core/diagnostics/internal_records.rb +8 -12
- data/lib/julewire/core/diagnostics/invalid_severity_reporter.rb +16 -55
- data/lib/julewire/core/diagnostics/meta_observer.rb +37 -44
- data/lib/julewire/core/diagnostics/process_integration_health.rb +0 -5
- data/lib/julewire/core/diagnostics/tail/renderer.rb +1 -1
- data/lib/julewire/core/diagnostics/tail.rb +18 -22
- data/lib/julewire/core/execution/boundary.rb +2 -8
- data/lib/julewire/core/execution/handle.rb +12 -17
- data/lib/julewire/core/execution/lineage.rb +16 -56
- data/lib/julewire/core/execution/measurement_handle.rb +6 -10
- data/lib/julewire/core/execution/scope.rb +15 -20
- data/lib/julewire/core/execution/scope_fields.rb +3 -12
- data/lib/julewire/core/execution/scope_identity.rb +1 -9
- data/lib/julewire/core/execution/scope_snapshot.rb +18 -39
- data/lib/julewire/core/execution/summary_state.rb +16 -19
- data/lib/julewire/core/execution/view.rb +8 -17
- data/lib/julewire/core/facade_methods.rb +67 -65
- data/lib/julewire/core/fields/attribute_keys.rb +0 -2
- data/lib/julewire/core/fields/bags.rb +23 -27
- data/lib/julewire/core/fields/field_set.rb +29 -19
- data/lib/julewire/core/fields/field_stack.rb +68 -134
- data/lib/julewire/core/fields/internal/deletion.rb +6 -9
- data/lib/julewire/core/fields/internal.rb +19 -38
- data/lib/julewire/core/fields/lookup.rb +9 -13
- data/lib/julewire/core/fields/section_proxy.rb +1 -9
- data/lib/julewire/core/fields/stack_set.rb +7 -12
- data/lib/julewire/core/fields/static_labels.rb +1 -1
- data/lib/julewire/core/integration/configurable.rb +4 -3
- data/lib/julewire/core/integration/destination_health.rb +17 -7
- data/lib/julewire/core/integration/event_subscriber.rb +1 -1
- data/lib/julewire/core/integration/facade.rb +12 -15
- data/lib/julewire/core/integration/fork_hooks.rb +12 -36
- data/lib/julewire/core/integration/health.rb +0 -3
- data/lib/julewire/core/integration/ivar_state.rb +0 -5
- data/lib/julewire/core/integration/protocol.rb +20 -0
- data/lib/julewire/core/integration/settings.rb +4 -4
- data/lib/julewire/core/integration/subscriber_install.rb +2 -2
- data/lib/julewire/core/integration/subscription.rb +3 -2
- data/lib/julewire/core/integration/values.rb +0 -17
- data/lib/julewire/core/local_storage.rb +3 -19
- data/lib/julewire/core/processing/invalid_result_failure.rb +23 -0
- data/lib/julewire/core/processing/level_threshold.rb +7 -14
- data/lib/julewire/core/processing/match.rb +6 -4
- data/lib/julewire/core/processing/pipeline.rb +46 -40
- data/lib/julewire/core/processing/processor_chain.rb +22 -11
- data/lib/julewire/core/processing/processor_registry.rb +3 -4
- data/lib/julewire/core/processing/record_field_transform.rb +0 -4
- data/lib/julewire/core/processing/sampling.rb +1 -3
- data/lib/julewire/core/processing.rb +2 -2
- data/lib/julewire/core/propagation/carrier.rb +14 -14
- data/lib/julewire/core/propagation.rb +15 -2
- data/lib/julewire/core/records/build_input.rb +75 -0
- data/lib/julewire/core/records/console_formatter.rb +6 -6
- data/lib/julewire/core/records/deconstruct.rb +1 -1
- data/lib/julewire/core/records/display_message.rb +2 -4
- data/lib/julewire/core/records/draft.rb +125 -262
- data/lib/julewire/core/records/lazy_emit_input.rb +2 -12
- data/lib/julewire/core/records/metadata.rb +4 -3
- data/lib/julewire/core/records/public_projection.rb +2 -2
- data/lib/julewire/core/records/raw_input.rb +1 -1
- data/lib/julewire/core/records/record.rb +19 -37
- data/lib/julewire/core/records/severity.rb +7 -15
- data/lib/julewire/core/runtime.rb +67 -71
- data/lib/julewire/core/runtime_registry.rb +20 -15
- data/lib/julewire/core/runtime_state.rb +5 -3
- data/lib/julewire/core/scheduling/shared_scheduler.rb +28 -22
- data/lib/julewire/core/serialization/backtrace_limiter.rb +13 -9
- data/lib/julewire/core/serialization/bounded_transform.rb +2 -12
- data/lib/julewire/core/serialization/bounded_traversal.rb +49 -66
- data/lib/julewire/core/serialization/deep_compact_empty.rb +9 -11
- data/lib/julewire/core/serialization/deep_freeze.rb +45 -6
- data/lib/julewire/core/serialization/encoding_sanitizer.rb +2 -3
- data/lib/julewire/core/serialization/exception_shape.rb +7 -6
- data/lib/julewire/core/serialization/json_encoder.rb +10 -13
- data/lib/julewire/core/serialization/serializer.rb +23 -50
- data/lib/julewire/core/serialization/serializer_pool.rb +9 -0
- data/lib/julewire/core/serialization/text_encoder.rb +5 -5
- data/lib/julewire/core/serialization/truncation_metadata.rb +63 -48
- data/lib/julewire/core/serialization/value_copy.rb +60 -227
- data/lib/julewire/core/serialization/value_traversal.rb +10 -127
- data/lib/julewire/core/testing.rb +6 -56
- data/lib/julewire/core/validation.rb +2 -3
- data/lib/julewire/core/version.rb +1 -1
- data/lib/julewire/core.rb +2 -7
- metadata +6 -19
- data/lib/julewire/core/scheduling/deadline_scheduler.rb +0 -207
- data/lib/julewire/core/testing/chaos/catalog.rb +0 -72
- data/lib/julewire/core/testing/chaos/core_runtime.rb +0 -120
- data/lib/julewire/core/testing/chaos/destination.rb +0 -55
- data/lib/julewire/core/testing/chaos/emitter.rb +0 -20
- data/lib/julewire/core/testing/chaos/raising_output.rb +0 -42
- data/lib/julewire/core/testing/chaos.rb +0 -80
- data/lib/julewire/core/testing/contracts/component.rb +0 -162
- data/lib/julewire/core/testing/contracts/deadline_scheduler.rb +0 -59
- data/lib/julewire/core/testing/contracts/integration.rb +0 -166
- data/lib/julewire/core/testing/contracts/integration_fields.rb +0 -36
- data/lib/julewire/core/testing/contracts/record_draft.rb +0 -37
- data/lib/julewire/core/testing/contracts/runtime.rb +0 -178
- data/lib/julewire/core/testing/contracts/wire.rb +0 -60
- data/lib/julewire/core/testing/contracts.rb +0 -24
- data/lib/julewire/core/testing/coverage.rb +0 -58
- data/lib/julewire/core/testing/test_reports.rb +0 -78
|
@@ -7,9 +7,8 @@ module Julewire
|
|
|
7
7
|
class << self
|
|
8
8
|
def validate_byte_limit!(value, name:)
|
|
9
9
|
return if value.nil?
|
|
10
|
+
return value if value.instance_of?(Integer) && value.positive?
|
|
10
11
|
|
|
11
|
-
validate_integer_limit!(value, name: name, positive: true)
|
|
12
|
-
rescue ArgumentError
|
|
13
12
|
raise ArgumentError, "#{name} must be nil or a positive Integer"
|
|
14
13
|
end
|
|
15
14
|
|
|
@@ -18,7 +17,7 @@ module Julewire
|
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
def validate_integer_limit!(value, name:, positive: false)
|
|
21
|
-
return value if value.
|
|
20
|
+
return value if value.instance_of?(Integer) && valid_integer_limit?(value, positive: positive)
|
|
22
21
|
|
|
23
22
|
qualifier = positive ? "positive" : "non-negative"
|
|
24
23
|
raise ArgumentError, "#{name} must be a #{qualifier} Integer"
|
data/lib/julewire/core.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Julewire
|
|
|
6
6
|
# Each gem extends the shared Julewire namespace.
|
|
7
7
|
loader = Zeitwerk::Loader.for_gem_extension(self)
|
|
8
8
|
loader.inflector.inflect("cli" => "CLI")
|
|
9
|
-
loader.ignore("#{__dir__}/core/testing.rb"
|
|
9
|
+
loader.ignore("#{__dir__}/core/testing.rb")
|
|
10
10
|
loader.setup
|
|
11
11
|
|
|
12
12
|
module Core
|
|
@@ -25,7 +25,7 @@ module Julewire
|
|
|
25
25
|
|
|
26
26
|
value.to_sym
|
|
27
27
|
when Symbol
|
|
28
|
-
raise ArgumentError, "#{name} must not be empty" if value.
|
|
28
|
+
raise ArgumentError, "#{name} must not be empty" if value.empty?
|
|
29
29
|
|
|
30
30
|
value
|
|
31
31
|
else
|
|
@@ -54,11 +54,6 @@ module Julewire
|
|
|
54
54
|
extend Core::FacadeMethods
|
|
55
55
|
|
|
56
56
|
Core::RuntimeLocator.current = Core::Runtime.new
|
|
57
|
-
Core.singleton_class.class_eval do
|
|
58
|
-
define_method(:loader) { loader }
|
|
59
|
-
private :loader
|
|
60
|
-
end
|
|
61
|
-
|
|
62
57
|
ConsoleFormatter = Core::Records::ConsoleFormatter
|
|
63
58
|
JsonEncoder = Core::Serialization::JsonEncoder
|
|
64
59
|
Match = Core::Processing::Match
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: julewire-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Grebennik
|
|
@@ -87,6 +87,7 @@ files:
|
|
|
87
87
|
- lib/julewire/core/destinations/collection.rb
|
|
88
88
|
- lib/julewire/core/destinations/definition.rb
|
|
89
89
|
- lib/julewire/core/destinations/destination.rb
|
|
90
|
+
- lib/julewire/core/destinations/processor_handling.rb
|
|
90
91
|
- lib/julewire/core/destinations/registry.rb
|
|
91
92
|
- lib/julewire/core/destinations/sink.rb
|
|
92
93
|
- lib/julewire/core/destinations/synchronized_output.rb
|
|
@@ -139,6 +140,7 @@ files:
|
|
|
139
140
|
- lib/julewire/core/integration/health.rb
|
|
140
141
|
- lib/julewire/core/integration/ivar_state.rb
|
|
141
142
|
- lib/julewire/core/integration/lifecycle.rb
|
|
143
|
+
- lib/julewire/core/integration/protocol.rb
|
|
142
144
|
- lib/julewire/core/integration/scoped.rb
|
|
143
145
|
- lib/julewire/core/integration/settings.rb
|
|
144
146
|
- lib/julewire/core/integration/subscriber_install.rb
|
|
@@ -147,6 +149,7 @@ files:
|
|
|
147
149
|
- lib/julewire/core/lifecycle_error.rb
|
|
148
150
|
- lib/julewire/core/local_storage.rb
|
|
149
151
|
- lib/julewire/core/processing.rb
|
|
152
|
+
- lib/julewire/core/processing/invalid_result_failure.rb
|
|
150
153
|
- lib/julewire/core/processing/level_threshold.rb
|
|
151
154
|
- lib/julewire/core/processing/match.rb
|
|
152
155
|
- lib/julewire/core/processing/pipeline.rb
|
|
@@ -157,6 +160,7 @@ files:
|
|
|
157
160
|
- lib/julewire/core/processing/sampling.rb
|
|
158
161
|
- lib/julewire/core/propagation.rb
|
|
159
162
|
- lib/julewire/core/propagation/carrier.rb
|
|
163
|
+
- lib/julewire/core/records/build_input.rb
|
|
160
164
|
- lib/julewire/core/records/console_formatter.rb
|
|
161
165
|
- lib/julewire/core/records/deconstruct.rb
|
|
162
166
|
- lib/julewire/core/records/display_message.rb
|
|
@@ -173,7 +177,6 @@ files:
|
|
|
173
177
|
- lib/julewire/core/runtime_registry.rb
|
|
174
178
|
- lib/julewire/core/runtime_state.rb
|
|
175
179
|
- lib/julewire/core/scheduling/deadline.rb
|
|
176
|
-
- lib/julewire/core/scheduling/deadline_scheduler.rb
|
|
177
180
|
- lib/julewire/core/scheduling/shared_scheduler.rb
|
|
178
181
|
- lib/julewire/core/sentinel.rb
|
|
179
182
|
- lib/julewire/core/serialization/backtrace_limiter.rb
|
|
@@ -191,22 +194,6 @@ files:
|
|
|
191
194
|
- lib/julewire/core/serialization/value_copy.rb
|
|
192
195
|
- lib/julewire/core/serialization/value_traversal.rb
|
|
193
196
|
- lib/julewire/core/testing.rb
|
|
194
|
-
- lib/julewire/core/testing/chaos.rb
|
|
195
|
-
- lib/julewire/core/testing/chaos/catalog.rb
|
|
196
|
-
- lib/julewire/core/testing/chaos/core_runtime.rb
|
|
197
|
-
- lib/julewire/core/testing/chaos/destination.rb
|
|
198
|
-
- lib/julewire/core/testing/chaos/emitter.rb
|
|
199
|
-
- lib/julewire/core/testing/chaos/raising_output.rb
|
|
200
|
-
- lib/julewire/core/testing/contracts.rb
|
|
201
|
-
- lib/julewire/core/testing/contracts/component.rb
|
|
202
|
-
- lib/julewire/core/testing/contracts/deadline_scheduler.rb
|
|
203
|
-
- lib/julewire/core/testing/contracts/integration.rb
|
|
204
|
-
- lib/julewire/core/testing/contracts/integration_fields.rb
|
|
205
|
-
- lib/julewire/core/testing/contracts/record_draft.rb
|
|
206
|
-
- lib/julewire/core/testing/contracts/runtime.rb
|
|
207
|
-
- lib/julewire/core/testing/contracts/wire.rb
|
|
208
|
-
- lib/julewire/core/testing/coverage.rb
|
|
209
|
-
- lib/julewire/core/testing/test_reports.rb
|
|
210
197
|
- lib/julewire/core/validation.rb
|
|
211
198
|
- lib/julewire/core/version.rb
|
|
212
199
|
- lib/julewire/error.rb
|
|
@@ -232,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
232
219
|
- !ruby/object:Gem::Version
|
|
233
220
|
version: '0'
|
|
234
221
|
requirements: []
|
|
235
|
-
rubygems_version: 4.0.
|
|
222
|
+
rubygems_version: 4.0.16
|
|
236
223
|
specification_version: 4
|
|
237
224
|
summary: Execution-scoped structured logging core for Ruby applications.
|
|
238
225
|
test_files: []
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Julewire
|
|
4
|
-
module Core
|
|
5
|
-
module Scheduling
|
|
6
|
-
# @api integration_spi
|
|
7
|
-
class DeadlineScheduler
|
|
8
|
-
CLOCK = Process::CLOCK_MONOTONIC
|
|
9
|
-
Entry = Data.define(:deadline, :token, :callback)
|
|
10
|
-
|
|
11
|
-
def initialize(thread_name:, idle: :keep_alive)
|
|
12
|
-
@thread_name = thread_name
|
|
13
|
-
@idle = idle
|
|
14
|
-
@mutex = Mutex.new
|
|
15
|
-
@condition = ConditionVariable.new
|
|
16
|
-
@entries = {}
|
|
17
|
-
# A heap keeps timeout scheduling cheap without non-shareable scheduler dependencies.
|
|
18
|
-
@heap = []
|
|
19
|
-
@next_token = 0
|
|
20
|
-
@generation = 0
|
|
21
|
-
@pid = Process.pid
|
|
22
|
-
@thread = nil
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def schedule(timeout, &block)
|
|
26
|
-
raise ArgumentError, "block required" unless block
|
|
27
|
-
|
|
28
|
-
timeout = Float(timeout)
|
|
29
|
-
if timeout <= 0
|
|
30
|
-
yield
|
|
31
|
-
return
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
@mutex.synchronize do
|
|
35
|
-
token = next_token
|
|
36
|
-
entry = Entry.new(monotonic_time + timeout, token, block)
|
|
37
|
-
@entries[token] = entry
|
|
38
|
-
heap_push(entry)
|
|
39
|
-
ensure_thread
|
|
40
|
-
@condition.signal
|
|
41
|
-
token
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def cancel(token)
|
|
46
|
-
return unless token
|
|
47
|
-
|
|
48
|
-
@mutex.synchronize do
|
|
49
|
-
@entries.delete(token)
|
|
50
|
-
@condition.signal
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def after_fork!
|
|
55
|
-
if @pid == Process.pid
|
|
56
|
-
reset_same_process
|
|
57
|
-
else
|
|
58
|
-
reset_after_fork
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
self
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
private
|
|
65
|
-
|
|
66
|
-
def reset_same_process
|
|
67
|
-
@mutex.synchronize do
|
|
68
|
-
@generation += 1
|
|
69
|
-
@entries = {}
|
|
70
|
-
@heap = []
|
|
71
|
-
@next_token = 0
|
|
72
|
-
@thread = nil
|
|
73
|
-
@condition.broadcast
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def reset_after_fork
|
|
78
|
-
@mutex = Mutex.new
|
|
79
|
-
@condition = ConditionVariable.new
|
|
80
|
-
@entries = {}
|
|
81
|
-
@heap = []
|
|
82
|
-
@next_token = 0
|
|
83
|
-
@generation += 1
|
|
84
|
-
@pid = Process.pid
|
|
85
|
-
@thread = nil
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def next_token
|
|
89
|
-
@next_token += 1
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def ensure_thread
|
|
93
|
-
return if @thread&.alive?
|
|
94
|
-
|
|
95
|
-
generation = @generation
|
|
96
|
-
@thread = Thread.new { run(generation) }
|
|
97
|
-
@thread.name = @thread_name
|
|
98
|
-
@thread.report_on_exception = false
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def run(generation)
|
|
102
|
-
loop do
|
|
103
|
-
callback = next_expired_callback(generation)
|
|
104
|
-
return unless callback
|
|
105
|
-
|
|
106
|
-
safe_call(callback)
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def next_expired_callback(generation)
|
|
111
|
-
@mutex.synchronize do
|
|
112
|
-
loop do
|
|
113
|
-
return unless generation == @generation
|
|
114
|
-
|
|
115
|
-
discard_cancelled_head
|
|
116
|
-
if @heap.empty?
|
|
117
|
-
return clear_thread if exit_when_idle?
|
|
118
|
-
|
|
119
|
-
@condition.wait(@mutex)
|
|
120
|
-
next
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
entry = @heap.fetch(0)
|
|
124
|
-
remaining = entry.deadline - monotonic_time
|
|
125
|
-
if remaining.positive?
|
|
126
|
-
@condition.wait(@mutex, remaining)
|
|
127
|
-
else
|
|
128
|
-
heap_pop
|
|
129
|
-
@entries.delete(entry.token)
|
|
130
|
-
return entry.callback
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def discard_cancelled_head
|
|
137
|
-
heap_pop while @heap.any? && !@entries.key?(@heap.fetch(0).token)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def clear_thread
|
|
141
|
-
@thread = nil
|
|
142
|
-
nil
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def exit_when_idle?
|
|
146
|
-
@idle == :exit
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def safe_call(callback)
|
|
150
|
-
callback.call
|
|
151
|
-
rescue StandardError
|
|
152
|
-
nil
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def monotonic_time
|
|
156
|
-
Process.clock_gettime(CLOCK)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def heap_push(entry)
|
|
160
|
-
@heap << entry
|
|
161
|
-
sift_up(@heap.length - 1)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def heap_pop
|
|
165
|
-
return @heap.pop if @heap.one?
|
|
166
|
-
|
|
167
|
-
top = @heap.fetch(0)
|
|
168
|
-
@heap[0] = @heap.pop
|
|
169
|
-
sift_down(0)
|
|
170
|
-
top
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def sift_up(index)
|
|
174
|
-
while index.positive?
|
|
175
|
-
parent = (index - 1) / 2
|
|
176
|
-
break if earlier_or_equal?(@heap.fetch(parent), @heap.fetch(index))
|
|
177
|
-
|
|
178
|
-
swap_heap(index, parent)
|
|
179
|
-
index = parent
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def sift_down(index)
|
|
184
|
-
loop do
|
|
185
|
-
left = (index * 2) + 1
|
|
186
|
-
right = left + 1
|
|
187
|
-
smallest = index
|
|
188
|
-
smallest = left if left < @heap.length && earlier_or_equal?(@heap.fetch(left), @heap.fetch(smallest))
|
|
189
|
-
smallest = right if right < @heap.length && earlier_or_equal?(@heap.fetch(right), @heap.fetch(smallest))
|
|
190
|
-
break if smallest == index
|
|
191
|
-
|
|
192
|
-
swap_heap(index, smallest)
|
|
193
|
-
index = smallest
|
|
194
|
-
end
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def earlier_or_equal?(left, right)
|
|
198
|
-
left.deadline < right.deadline || (left.deadline == right.deadline && left.token <= right.token)
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def swap_heap(left, right)
|
|
202
|
-
@heap[left], @heap[right] = @heap[right], @heap[left]
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
end
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Julewire
|
|
4
|
-
module Core
|
|
5
|
-
module Testing
|
|
6
|
-
module Chaos
|
|
7
|
-
class Catalog
|
|
8
|
-
Entry = Data.define(:kind, :name, :exercise)
|
|
9
|
-
KINDS = %i[processor formatter encoder destination subscriber listener].freeze
|
|
10
|
-
|
|
11
|
-
attr_reader :entries
|
|
12
|
-
|
|
13
|
-
class << self
|
|
14
|
-
def build
|
|
15
|
-
catalog = new
|
|
16
|
-
yield catalog if block_given?
|
|
17
|
-
catalog
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def assert_contract(test_context, catalog:, errors:)
|
|
21
|
-
entries = catalog.entries
|
|
22
|
-
raise ArgumentError, "chaos catalog must have entries" if entries.empty?
|
|
23
|
-
|
|
24
|
-
entries.each do |entry|
|
|
25
|
-
assert_entry(test_context, entry, errors)
|
|
26
|
-
end
|
|
27
|
-
nil
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
def assert_entry(test_context, entry, errors)
|
|
33
|
-
Chaos.assert_contained(
|
|
34
|
-
test_context,
|
|
35
|
-
errors: errors,
|
|
36
|
-
description: "#{entry.kind} #{entry.name}"
|
|
37
|
-
) do |error|
|
|
38
|
-
entry.exercise.call(error)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def initialize
|
|
44
|
-
@entries = []
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def processor(name, &) = register(:processor, name, &)
|
|
48
|
-
|
|
49
|
-
def formatter(name, &) = register(:formatter, name, &)
|
|
50
|
-
|
|
51
|
-
def encoder(name, &) = register(:encoder, name, &)
|
|
52
|
-
|
|
53
|
-
def destination(name, &) = register(:destination, name, &)
|
|
54
|
-
|
|
55
|
-
def subscriber(name, &) = register(:subscriber, name, &)
|
|
56
|
-
|
|
57
|
-
def listener(name, &) = register(:listener, name, &)
|
|
58
|
-
|
|
59
|
-
private
|
|
60
|
-
|
|
61
|
-
def register(kind, name, &exercise)
|
|
62
|
-
raise ArgumentError, "unknown chaos component kind #{kind.inspect}" unless KINDS.include?(kind)
|
|
63
|
-
raise ArgumentError, "chaos component exercise block required" unless exercise
|
|
64
|
-
|
|
65
|
-
@entries << Entry.new(kind, Core.normalize_name(name), exercise)
|
|
66
|
-
self
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Julewire
|
|
4
|
-
module Core
|
|
5
|
-
module Testing
|
|
6
|
-
module Chaos
|
|
7
|
-
module CoreRuntime
|
|
8
|
-
SCENARIOS = %i[
|
|
9
|
-
destination_processor
|
|
10
|
-
drop_callback
|
|
11
|
-
encoder
|
|
12
|
-
failure_callback
|
|
13
|
-
formatter
|
|
14
|
-
lifecycle_after_fork
|
|
15
|
-
lifecycle_flush
|
|
16
|
-
output
|
|
17
|
-
pipeline_processor
|
|
18
|
-
].freeze
|
|
19
|
-
|
|
20
|
-
private_constant :SCENARIOS
|
|
21
|
-
|
|
22
|
-
class << self
|
|
23
|
-
def assert_contract(test_context, runtime:, reset:, errors:)
|
|
24
|
-
SCENARIOS.each do |scenario|
|
|
25
|
-
errors.each do |error|
|
|
26
|
-
assert_scenario(test_context, runtime, reset, scenario, error)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
nil
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def assert_scenario(test_context, runtime, reset, scenario, error)
|
|
35
|
-
reset.call
|
|
36
|
-
send(:"exercise_#{scenario}", runtime, error)
|
|
37
|
-
rescue StandardError => e
|
|
38
|
-
test_context.flunk(
|
|
39
|
-
"expected core #{scenario} failure to be contained, " \
|
|
40
|
-
"#{error.class} leaked #{e.class}: #{e.message}"
|
|
41
|
-
)
|
|
42
|
-
ensure
|
|
43
|
-
reset.call
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def exercise_destination_processor(runtime, error)
|
|
47
|
-
configure_destination(runtime, processors: [Chaos.raiser(error)])
|
|
48
|
-
runtime.emit("chaos")
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def exercise_drop_callback(runtime, error)
|
|
52
|
-
trigger = RuntimeError.new("julewire chaos formatter trigger")
|
|
53
|
-
configure_destination(runtime, formatter: Chaos.raiser(trigger), on_drop: Chaos.raiser(error))
|
|
54
|
-
runtime.emit("chaos")
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def exercise_encoder(runtime, error)
|
|
58
|
-
configure_destination(runtime, encoder: Chaos.raiser(error))
|
|
59
|
-
runtime.emit("chaos")
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def exercise_failure_callback(runtime, error)
|
|
63
|
-
trigger = RuntimeError.new("julewire chaos output trigger")
|
|
64
|
-
configure_destination(
|
|
65
|
-
runtime,
|
|
66
|
-
output: RaisingOutput.new(trigger, failures: %i[write]),
|
|
67
|
-
runtime_on_failure: Chaos.raiser(error)
|
|
68
|
-
)
|
|
69
|
-
runtime.emit("chaos")
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def exercise_formatter(runtime, error)
|
|
73
|
-
configure_destination(runtime, formatter: Chaos.raiser(error))
|
|
74
|
-
runtime.emit("chaos")
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def exercise_lifecycle_after_fork(runtime, error)
|
|
78
|
-
configure_destination(runtime, output: RaisingOutput.new(error, failures: %i[after_fork]))
|
|
79
|
-
runtime.after_fork!
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def exercise_lifecycle_flush(runtime, error)
|
|
83
|
-
configure_destination(runtime, output: RaisingOutput.new(error, failures: %i[flush]))
|
|
84
|
-
runtime.flush
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def exercise_output(runtime, error)
|
|
88
|
-
configure_destination(runtime, output: RaisingOutput.new(error, failures: %i[write]))
|
|
89
|
-
runtime.emit("chaos")
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def exercise_pipeline_processor(runtime, error)
|
|
93
|
-
runtime.configure do |config|
|
|
94
|
-
config.destinations.use(:default, output: NullOutput.new)
|
|
95
|
-
config.processors.use(Chaos.raiser(error))
|
|
96
|
-
end
|
|
97
|
-
runtime.emit("chaos")
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def configure_destination(runtime, output: NullOutput.new, formatter: nil, encoder: nil,
|
|
101
|
-
on_drop: nil, processors: nil, runtime_on_failure: nil)
|
|
102
|
-
runtime.configure do |config|
|
|
103
|
-
config.on_failure = runtime_on_failure if runtime_on_failure
|
|
104
|
-
config.destinations.clear
|
|
105
|
-
config.destinations.use(
|
|
106
|
-
:default,
|
|
107
|
-
encoder: encoder || Julewire::Core::Serialization::JsonEncoder.new,
|
|
108
|
-
formatter: formatter || Julewire::Core::Records::Formatter.new,
|
|
109
|
-
on_drop: on_drop,
|
|
110
|
-
output: output,
|
|
111
|
-
processors: processors || []
|
|
112
|
-
)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Julewire
|
|
4
|
-
module Core
|
|
5
|
-
module Testing
|
|
6
|
-
module Chaos
|
|
7
|
-
module Destination
|
|
8
|
-
class << self
|
|
9
|
-
def assert_contract(test_context, record:, formatter:, encoder:, output:, callbacks:, errors:)
|
|
10
|
-
{
|
|
11
|
-
formatter: formatter,
|
|
12
|
-
encoder: encoder,
|
|
13
|
-
output: output,
|
|
14
|
-
callbacks: callbacks
|
|
15
|
-
}.compact.each do |scenario, builder|
|
|
16
|
-
assert_scenario(test_context, scenario, builder, record, errors)
|
|
17
|
-
end
|
|
18
|
-
nil
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def assert_scenario(test_context, scenario, builder, record, errors)
|
|
24
|
-
errors.each do |error|
|
|
25
|
-
assert_error_contained(test_context, scenario, builder, record, error)
|
|
26
|
-
end
|
|
27
|
-
nil
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def assert_error_contained(test_context, scenario, builder, record, error)
|
|
31
|
-
Chaos.assert_contained(
|
|
32
|
-
test_context,
|
|
33
|
-
errors: [error],
|
|
34
|
-
description: "destination #{scenario}"
|
|
35
|
-
) do |build_error|
|
|
36
|
-
destination = builder.call(build_error)
|
|
37
|
-
destination.emit(record)
|
|
38
|
-
ensure
|
|
39
|
-
close_destination(destination)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def close_destination(destination)
|
|
44
|
-
return unless destination.respond_to?(:close)
|
|
45
|
-
|
|
46
|
-
destination.close(timeout: 0)
|
|
47
|
-
rescue StandardError
|
|
48
|
-
nil
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Julewire
|
|
4
|
-
module Core
|
|
5
|
-
module Testing
|
|
6
|
-
module Chaos
|
|
7
|
-
module Emitter
|
|
8
|
-
class << self
|
|
9
|
-
def assert_contract(test_context, component:, build:, exercise:, errors:)
|
|
10
|
-
Chaos.assert_contained(test_context, errors: errors, description: component) do |error|
|
|
11
|
-
emitter = build.call(error)
|
|
12
|
-
exercise.call(emitter, error)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Julewire
|
|
4
|
-
module Core
|
|
5
|
-
module Testing
|
|
6
|
-
module Chaos
|
|
7
|
-
class RaisingOutput
|
|
8
|
-
def initialize(error, failures:)
|
|
9
|
-
@error = error
|
|
10
|
-
@failures = failures
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def write(value)
|
|
14
|
-
raise @error if @failures.include?(:write)
|
|
15
|
-
|
|
16
|
-
value.bytesize
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def flush
|
|
20
|
-
raise @error if @failures.include?(:flush)
|
|
21
|
-
|
|
22
|
-
self
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def close
|
|
26
|
-
raise @error if @failures.include?(:close)
|
|
27
|
-
|
|
28
|
-
self
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def after_fork!
|
|
32
|
-
raise @error if @failures.include?(:after_fork)
|
|
33
|
-
|
|
34
|
-
self
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private_constant :RaisingOutput
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|