legionio 1.7.8 → 1.7.13
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/.rubocop.yml +3 -1
- data/CHANGELOG.md +25 -0
- data/legionio.gemspec +8 -8
- data/lib/legion/api/audit.rb +1 -1
- data/lib/legion/api/events.rb +38 -15
- data/lib/legion/api/helpers.rb +29 -7
- data/lib/legion/api/library_routes.rb +3 -0
- data/lib/legion/api/tenants.rb +5 -6
- data/lib/legion/api/workers.rb +1 -14
- data/lib/legion/api.rb +21 -2
- data/lib/legion/cli/chat/chat_logger.rb +19 -12
- data/lib/legion/cli/config_command.rb +1 -1
- data/lib/legion/cli/error_handler.rb +8 -2
- data/lib/legion/cli/start.rb +3 -2
- data/lib/legion/cli.rb +13 -2
- data/lib/legion/extensions/catalog.rb +77 -11
- data/lib/legion/extensions/core.rb +23 -6
- data/lib/legion/extensions/helpers/secret.rb +2 -0
- data/lib/legion/extensions/transport.rb +15 -2
- data/lib/legion/region.rb +36 -1
- data/lib/legion/service.rb +174 -127
- data/lib/legion/task_outcome_observer.rb +32 -8
- data/lib/legion/telemetry.rb +19 -11
- data/lib/legion/version.rb +1 -1
- data/lib/legion/webhooks.rb +169 -40
- metadata +17 -17
|
@@ -41,7 +41,7 @@ module Legion
|
|
|
41
41
|
record_learning(domain: domain, success: success)
|
|
42
42
|
publish_lesson(runner: runner_class, function: function, success: success)
|
|
43
43
|
rescue StandardError => e
|
|
44
|
-
Legion::Logging.
|
|
44
|
+
Legion::Logging.warn "[TaskOutcomeObserver] handle_outcome error: #{e.class}: #{e.message}" if defined?(Legion::Logging)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def derive_domain(runner_class)
|
|
@@ -53,13 +53,15 @@ module Legion
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def record_learning(domain:, success:)
|
|
56
|
-
|
|
56
|
+
client = meta_learning_client
|
|
57
|
+
return unless client
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
domain_id = resolve_learning_domain_id(client, domain)
|
|
60
|
+
return unless domain_id
|
|
61
|
+
|
|
62
|
+
client.record_learning_episode(domain_id: domain_id, success: success)
|
|
61
63
|
rescue StandardError => e
|
|
62
|
-
Legion::Logging.
|
|
64
|
+
Legion::Logging.warn "[TaskOutcomeObserver] record_learning failed: #{e.class}: #{e.message}" if defined?(Legion::Logging)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
67
|
def publish_lesson(runner:, function:, success:, **_opts)
|
|
@@ -76,7 +78,7 @@ module Legion
|
|
|
76
78
|
is_inference: false
|
|
77
79
|
)
|
|
78
80
|
rescue StandardError => e
|
|
79
|
-
Legion::Logging.
|
|
81
|
+
Legion::Logging.warn "[TaskOutcomeObserver] publish_lesson failed: #{e.class}: #{e.message}" if defined?(Legion::Logging)
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
def setup_llm_reflection_hook
|
|
@@ -94,7 +96,29 @@ module Legion
|
|
|
94
96
|
Legion::LLM::Hooks::Reflection.install
|
|
95
97
|
Legion::Logging.info '[TaskOutcomeObserver] LLM reflection hook auto-installed'
|
|
96
98
|
rescue StandardError => e
|
|
97
|
-
Legion::Logging.
|
|
99
|
+
Legion::Logging.warn "[TaskOutcomeObserver] LLM reflection hook install failed: #{e.class}: #{e.message}" if defined?(Legion::Logging)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def meta_learning_client
|
|
103
|
+
return unless defined?(Legion::Extensions::Agentic::Learning::MetaLearning::Client)
|
|
104
|
+
|
|
105
|
+
@meta_learning_client ||= Legion::Extensions::Agentic::Learning::MetaLearning::Client.new
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def resolve_learning_domain_id(client, domain)
|
|
109
|
+
domain_map = learning_domain_map
|
|
110
|
+
return domain_map[domain] if domain_map.key?(domain)
|
|
111
|
+
|
|
112
|
+
result = client.create_learning_domain(name: domain)
|
|
113
|
+
return if result.is_a?(Hash) && result[:error]
|
|
114
|
+
|
|
115
|
+
domain_id = result[:id]
|
|
116
|
+
domain_map[domain] = domain_id if domain_id
|
|
117
|
+
domain_id
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def learning_domain_map
|
|
121
|
+
@learning_domain_map ||= {}
|
|
98
122
|
end
|
|
99
123
|
end
|
|
100
124
|
end
|
data/lib/legion/telemetry.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'legion/logging/helper'
|
|
4
|
+
|
|
3
5
|
module Legion
|
|
4
6
|
module Telemetry
|
|
7
|
+
extend Legion::Logging::Helper
|
|
8
|
+
|
|
5
9
|
autoload :OpenInference, 'legion/telemetry/open_inference'
|
|
6
10
|
autoload :SafetyMetrics, 'legion/telemetry/safety_metrics'
|
|
7
11
|
|
|
@@ -11,14 +15,14 @@ module Legion
|
|
|
11
15
|
defined?(OpenTelemetry::Trace) &&
|
|
12
16
|
OpenTelemetry::Trace.current_span != OpenTelemetry::Trace::Span::INVALID
|
|
13
17
|
rescue StandardError => e
|
|
14
|
-
|
|
18
|
+
handle_exception(e, level: :debug, operation: 'telemetry.otel_available')
|
|
15
19
|
false
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
def enabled?
|
|
19
23
|
defined?(OpenTelemetry::SDK) ? true : false
|
|
20
24
|
rescue StandardError => e
|
|
21
|
-
|
|
25
|
+
handle_exception(e, level: :debug, operation: 'telemetry.enabled')
|
|
22
26
|
false
|
|
23
27
|
end
|
|
24
28
|
|
|
@@ -29,13 +33,13 @@ module Legion
|
|
|
29
33
|
return
|
|
30
34
|
end
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
log.debug { "[Telemetry] starting span=#{name} kind=#{kind}" }
|
|
33
37
|
tracer = OpenTelemetry.tracer_provider.tracer('legion', Legion::VERSION)
|
|
34
38
|
tracer.in_span(name, kind: kind, attributes: sanitize_attributes(attributes), &)
|
|
35
39
|
rescue StandardError => e
|
|
36
40
|
raise if block_given? && !otel_init_error?(e)
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
handle_exception(e, level: :debug, operation: 'telemetry.with_span', span_name: name, kind: kind)
|
|
39
43
|
yield(nil) if block_given?
|
|
40
44
|
end
|
|
41
45
|
|
|
@@ -45,7 +49,7 @@ module Legion
|
|
|
45
49
|
span.record_exception(exception)
|
|
46
50
|
span.status = OpenTelemetry::Trace::Status.error(exception.message)
|
|
47
51
|
rescue StandardError => e
|
|
48
|
-
|
|
52
|
+
handle_exception(e, level: :debug, operation: 'telemetry.record_exception')
|
|
49
53
|
nil
|
|
50
54
|
end
|
|
51
55
|
|
|
@@ -60,7 +64,7 @@ module Legion
|
|
|
60
64
|
[k.to_s, val]
|
|
61
65
|
end
|
|
62
66
|
rescue StandardError => e
|
|
63
|
-
|
|
67
|
+
handle_exception(e, level: :debug, operation: 'telemetry.sanitize_attributes')
|
|
64
68
|
{}
|
|
65
69
|
end
|
|
66
70
|
|
|
@@ -82,14 +86,14 @@ module Legion
|
|
|
82
86
|
tracing = telemetry[:tracing]
|
|
83
87
|
tracing.is_a?(Hash) ? tracing : {}
|
|
84
88
|
rescue StandardError => e
|
|
85
|
-
|
|
89
|
+
handle_exception(e, level: :debug, operation: 'telemetry.tracing_settings')
|
|
86
90
|
{}
|
|
87
91
|
end
|
|
88
92
|
|
|
89
93
|
def otel_init_error?(error)
|
|
90
94
|
error.message.include?('OpenTelemetry') || error.message.include?('tracer')
|
|
91
95
|
rescue StandardError => e
|
|
92
|
-
|
|
96
|
+
handle_exception(e, level: :debug, operation: 'telemetry.otel_init_error?')
|
|
93
97
|
false
|
|
94
98
|
end
|
|
95
99
|
|
|
@@ -111,10 +115,13 @@ module Legion
|
|
|
111
115
|
)
|
|
112
116
|
|
|
113
117
|
OpenTelemetry.tracer_provider.add_span_processor(processor)
|
|
114
|
-
|
|
118
|
+
log.info "OTLP exporter configured: #{endpoint}"
|
|
115
119
|
true
|
|
116
120
|
rescue LoadError
|
|
117
|
-
|
|
121
|
+
log.warn 'opentelemetry-exporter-otlp gem not available'
|
|
122
|
+
false
|
|
123
|
+
rescue StandardError => e
|
|
124
|
+
handle_exception(e, level: :warn, operation: 'telemetry.configure_otlp', endpoint: endpoint)
|
|
118
125
|
false
|
|
119
126
|
end
|
|
120
127
|
|
|
@@ -124,9 +131,10 @@ module Legion
|
|
|
124
131
|
exporter = OpenTelemetry::SDK::Trace::Export::ConsoleSpanExporter.new
|
|
125
132
|
processor = OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(exporter)
|
|
126
133
|
OpenTelemetry.tracer_provider.add_span_processor(processor)
|
|
134
|
+
log.info 'Console telemetry exporter configured'
|
|
127
135
|
true
|
|
128
136
|
rescue StandardError => e
|
|
129
|
-
|
|
137
|
+
handle_exception(e, level: :debug, operation: 'telemetry.configure_console')
|
|
130
138
|
false
|
|
131
139
|
end
|
|
132
140
|
end
|
data/lib/legion/version.rb
CHANGED
data/lib/legion/webhooks.rb
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
require 'openssl'
|
|
4
4
|
require 'net/http'
|
|
5
5
|
require 'uri'
|
|
6
|
+
require 'legion/logging/helper'
|
|
6
7
|
|
|
7
8
|
module Legion
|
|
8
9
|
module Webhooks
|
|
10
|
+
DISPATCH_CACHE_TTL = 5
|
|
11
|
+
|
|
9
12
|
class << self
|
|
13
|
+
include Legion::Logging::Helper
|
|
14
|
+
|
|
10
15
|
def register(url:, secret:, event_types: ['*'], max_retries: 5, **)
|
|
11
16
|
return { error: 'data_unavailable' } unless db_available?
|
|
12
17
|
|
|
@@ -19,6 +24,7 @@ module Legion
|
|
|
19
24
|
created_at: Time.now.utc,
|
|
20
25
|
updated_at: Time.now.utc
|
|
21
26
|
)
|
|
27
|
+
invalidate_dispatch_cache!
|
|
22
28
|
{ registered: true, id: id }
|
|
23
29
|
end
|
|
24
30
|
|
|
@@ -26,6 +32,7 @@ module Legion
|
|
|
26
32
|
return { error: 'data_unavailable' } unless db_available?
|
|
27
33
|
|
|
28
34
|
Legion::Data.connection[:webhooks].where(id: id).delete
|
|
35
|
+
invalidate_dispatch_cache!
|
|
29
36
|
{ unregistered: true }
|
|
30
37
|
end
|
|
31
38
|
|
|
@@ -38,26 +45,111 @@ module Legion
|
|
|
38
45
|
def dispatch(event_name, payload)
|
|
39
46
|
return unless db_available?
|
|
40
47
|
|
|
41
|
-
webhooks =
|
|
48
|
+
webhooks = active_dispatch_webhooks
|
|
42
49
|
webhooks.each do |wh|
|
|
43
|
-
patterns =
|
|
44
|
-
Legion::JSON.load(wh[:event_types])
|
|
45
|
-
rescue StandardError => e
|
|
46
|
-
Legion::Logging.debug("Webhooks#dispatch event_types parse failed: #{e.message}") if defined?(Legion::Logging)
|
|
47
|
-
['*']
|
|
48
|
-
end
|
|
50
|
+
patterns = event_patterns_for(wh, event_name: event_name)
|
|
49
51
|
next unless patterns.any? { |p| File.fnmatch?(p, event_name) }
|
|
50
52
|
|
|
53
|
+
log.debug { "[Webhooks] dispatching event=#{event_name} webhook_id=#{wh[:id]} patterns=#{patterns.size}" }
|
|
51
54
|
deliver(wh, event_name, payload)
|
|
52
55
|
end
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
def deliver(webhook, event_name, payload, attempt: 1)
|
|
56
|
-
|
|
57
|
-
body =
|
|
59
|
+
log.info "[Webhooks] delivery attempt #{attempt} for event=#{event_name} url=#{webhook[:url]}"
|
|
60
|
+
body = delivery_body(event_name, payload)
|
|
58
61
|
signature = compute_signature(webhook[:secret], body)
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
response = perform_delivery_request(webhook[:url], event_name, body, signature)
|
|
64
|
+
success = response.code.to_i < 400
|
|
65
|
+
|
|
66
|
+
if success
|
|
67
|
+
log.info "[Webhooks] delivered event=#{event_name} status=#{response.code}"
|
|
68
|
+
else
|
|
69
|
+
log.warn "[Webhooks] delivery failed event=#{event_name} status=#{response.code} url=#{webhook[:url]}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
handle_delivery_response(
|
|
73
|
+
webhook: webhook,
|
|
74
|
+
event_name: event_name,
|
|
75
|
+
payload: payload,
|
|
76
|
+
response: response,
|
|
77
|
+
success: success,
|
|
78
|
+
attempt: attempt
|
|
79
|
+
)
|
|
80
|
+
rescue StandardError => e
|
|
81
|
+
handle_exception(
|
|
82
|
+
e,
|
|
83
|
+
level: :error,
|
|
84
|
+
operation: 'webhooks.deliver',
|
|
85
|
+
event_name: event_name,
|
|
86
|
+
webhook_id: webhook[:id],
|
|
87
|
+
attempt: attempt,
|
|
88
|
+
url: webhook[:url]
|
|
89
|
+
)
|
|
90
|
+
handle_delivery_exception(webhook, event_name, payload, attempt, e)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def compute_signature(secret, body)
|
|
94
|
+
OpenSSL::HMAC.hexdigest('SHA256', secret, body)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def invalidate_dispatch_cache!
|
|
100
|
+
@active_webhooks_cache = nil
|
|
101
|
+
@active_webhooks_cached_at = nil
|
|
102
|
+
@pattern_cache = {}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def active_dispatch_webhooks
|
|
106
|
+
cache_valid = @active_webhooks_cache && @active_webhooks_cached_at &&
|
|
107
|
+
(monotonic_now - @active_webhooks_cached_at) < DISPATCH_CACHE_TTL
|
|
108
|
+
return @active_webhooks_cache if cache_valid
|
|
109
|
+
|
|
110
|
+
@active_webhooks_cache = Legion::Data.connection[:webhooks].where(status: 'active').all
|
|
111
|
+
@active_webhooks_cached_at = monotonic_now
|
|
112
|
+
@active_webhooks_cache
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def monotonic_now
|
|
116
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def event_patterns_for(webhook, event_name:)
|
|
120
|
+
@pattern_cache ||= {}
|
|
121
|
+
cached_entry = @pattern_cache[webhook[:id]]
|
|
122
|
+
|
|
123
|
+
if cached_entry &&
|
|
124
|
+
cached_entry[:updated_at] == webhook[:updated_at] &&
|
|
125
|
+
cached_entry[:event_types] == webhook[:event_types]
|
|
126
|
+
return cached_entry[:patterns]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
patterns = parse_event_patterns(webhook[:event_types], webhook_id: webhook[:id], event_name: event_name)
|
|
130
|
+
@pattern_cache[webhook[:id]] = {
|
|
131
|
+
updated_at: webhook[:updated_at],
|
|
132
|
+
event_types: webhook[:event_types],
|
|
133
|
+
patterns: patterns
|
|
134
|
+
}
|
|
135
|
+
patterns
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def parse_event_patterns(raw_event_types, webhook_id:, event_name:)
|
|
139
|
+
parsed = Legion::JSON.load(raw_event_types)
|
|
140
|
+
Array(parsed).map(&:to_s).reject(&:empty?).then { |patterns| patterns.empty? ? ['*'] : patterns }
|
|
141
|
+
rescue StandardError => e
|
|
142
|
+
handle_exception(e, level: :debug, operation: 'webhooks.dispatch.parse_event_types',
|
|
143
|
+
event_name: event_name, webhook_id: webhook_id)
|
|
144
|
+
['*']
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def delivery_body(event_name, payload)
|
|
148
|
+
Legion::JSON.dump({ event: event_name, payload: payload, timestamp: Time.now.utc.iso8601 })
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def perform_delivery_request(url, event_name, body, signature)
|
|
152
|
+
uri = URI.parse(url)
|
|
61
153
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
62
154
|
http.use_ssl = uri.scheme == 'https'
|
|
63
155
|
http.open_timeout = 5
|
|
@@ -68,54 +160,90 @@ module Legion
|
|
|
68
160
|
request['X-Legion-Signature'] = "sha256=#{signature}"
|
|
69
161
|
request['X-Legion-Event'] = event_name
|
|
70
162
|
request.body = body
|
|
163
|
+
http.request(request)
|
|
164
|
+
end
|
|
71
165
|
|
|
72
|
-
|
|
73
|
-
|
|
166
|
+
def handle_delivery_response(delivery)
|
|
167
|
+
error_message = "http_status=#{delivery[:response].code}" unless delivery[:success]
|
|
168
|
+
record_delivery(
|
|
169
|
+
webhook_id: delivery[:webhook][:id],
|
|
170
|
+
event_name: delivery[:event_name],
|
|
171
|
+
status: delivery[:response].code.to_i,
|
|
172
|
+
success: delivery[:success],
|
|
173
|
+
error: error_message,
|
|
174
|
+
attempt: delivery[:attempt]
|
|
175
|
+
)
|
|
176
|
+
return { delivered: true, status: delivery[:response].code.to_i } if delivery[:success]
|
|
74
177
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
178
|
+
finalize_failure(
|
|
179
|
+
webhook: delivery[:webhook],
|
|
180
|
+
event_name: delivery[:event_name],
|
|
181
|
+
payload: delivery[:payload],
|
|
182
|
+
attempt: delivery[:attempt],
|
|
183
|
+
error: error_message,
|
|
184
|
+
response_status: delivery[:response].code.to_i
|
|
185
|
+
)
|
|
186
|
+
end
|
|
80
187
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
188
|
+
def handle_delivery_exception(webhook, event_name, payload, attempt, error)
|
|
189
|
+
record_delivery(
|
|
190
|
+
webhook_id: webhook[:id],
|
|
191
|
+
event_name: event_name,
|
|
192
|
+
status: nil,
|
|
193
|
+
success: false,
|
|
194
|
+
error: error.message,
|
|
195
|
+
attempt: attempt
|
|
196
|
+
)
|
|
197
|
+
finalize_failure(
|
|
198
|
+
webhook: webhook,
|
|
199
|
+
event_name: event_name,
|
|
200
|
+
payload: payload,
|
|
201
|
+
attempt: attempt,
|
|
202
|
+
error: error.message
|
|
203
|
+
)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def finalize_failure(failure)
|
|
207
|
+
if retry_pending?(failure[:webhook], failure[:attempt])
|
|
208
|
+
next_attempt = failure[:attempt] + 1
|
|
209
|
+
log.warn "[Webhooks] retrying event=#{failure[:event_name]} next_attempt=#{next_attempt}"
|
|
210
|
+
return deliver(failure[:webhook], failure[:event_name], failure[:payload], attempt: next_attempt)
|
|
92
211
|
end
|
|
212
|
+
|
|
213
|
+
dead_letter(failure[:webhook][:id], failure[:event_name], failure[:payload], failure[:attempt], failure[:error])
|
|
214
|
+
{ delivered: false, error: failure[:error], dead_lettered: true, status: failure[:response_status] }
|
|
93
215
|
end
|
|
94
216
|
|
|
95
|
-
def
|
|
96
|
-
|
|
217
|
+
def retry_pending?(webhook, attempt)
|
|
218
|
+
attempt <= retry_limit(webhook)
|
|
97
219
|
end
|
|
98
220
|
|
|
99
|
-
|
|
221
|
+
def retry_limit(webhook)
|
|
222
|
+
retries = webhook[:max_retries].to_i
|
|
223
|
+
retries.negative? ? 0 : retries
|
|
224
|
+
end
|
|
100
225
|
|
|
101
226
|
def db_available?
|
|
102
227
|
defined?(Legion::Data) && Legion::Data.respond_to?(:connection) && Legion::Data.connection
|
|
103
228
|
rescue StandardError => e
|
|
104
|
-
|
|
229
|
+
handle_exception(e, level: :debug, operation: 'webhooks.db_available?')
|
|
105
230
|
false
|
|
106
231
|
end
|
|
107
232
|
|
|
108
|
-
def record_delivery(
|
|
233
|
+
def record_delivery(delivery)
|
|
109
234
|
Legion::Data.connection[:webhook_deliveries].insert(
|
|
110
|
-
webhook_id: webhook_id,
|
|
111
|
-
event_name: event_name,
|
|
112
|
-
response_status: status,
|
|
113
|
-
success: success,
|
|
114
|
-
|
|
235
|
+
webhook_id: delivery[:webhook_id],
|
|
236
|
+
event_name: delivery[:event_name],
|
|
237
|
+
response_status: delivery[:status],
|
|
238
|
+
success: delivery[:success],
|
|
239
|
+
attempt: delivery.fetch(:attempt, 1),
|
|
240
|
+
error: delivery[:error],
|
|
115
241
|
delivered_at: Time.now.utc
|
|
116
242
|
)
|
|
117
243
|
rescue StandardError => e
|
|
118
|
-
|
|
244
|
+
handle_exception(e, level: :debug, operation: 'webhooks.record_delivery',
|
|
245
|
+
webhook_id: delivery[:webhook_id], event_name: delivery[:event_name],
|
|
246
|
+
status: delivery[:status], success: delivery[:success], attempt: delivery.fetch(:attempt, 1))
|
|
119
247
|
nil
|
|
120
248
|
end
|
|
121
249
|
|
|
@@ -129,7 +257,8 @@ module Legion
|
|
|
129
257
|
created_at: Time.now.utc
|
|
130
258
|
)
|
|
131
259
|
rescue StandardError => e
|
|
132
|
-
|
|
260
|
+
handle_exception(e, level: :debug, operation: 'webhooks.dead_letter',
|
|
261
|
+
webhook_id: webhook_id, event_name: event_name, attempts: attempts)
|
|
133
262
|
nil
|
|
134
263
|
end
|
|
135
264
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legionio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.7.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.7.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: kramdown
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -225,42 +225,42 @@ dependencies:
|
|
|
225
225
|
requirements:
|
|
226
226
|
- - ">="
|
|
227
227
|
- !ruby/object:Gem::Version
|
|
228
|
-
version: 1.3.
|
|
228
|
+
version: 1.3.22
|
|
229
229
|
type: :runtime
|
|
230
230
|
prerelease: false
|
|
231
231
|
version_requirements: !ruby/object:Gem::Requirement
|
|
232
232
|
requirements:
|
|
233
233
|
- - ">="
|
|
234
234
|
- !ruby/object:Gem::Version
|
|
235
|
-
version: 1.3.
|
|
235
|
+
version: 1.3.22
|
|
236
236
|
- !ruby/object:Gem::Dependency
|
|
237
237
|
name: legion-crypt
|
|
238
238
|
requirement: !ruby/object:Gem::Requirement
|
|
239
239
|
requirements:
|
|
240
240
|
- - ">="
|
|
241
241
|
- !ruby/object:Gem::Version
|
|
242
|
-
version: 1.
|
|
242
|
+
version: 1.5.1
|
|
243
243
|
type: :runtime
|
|
244
244
|
prerelease: false
|
|
245
245
|
version_requirements: !ruby/object:Gem::Requirement
|
|
246
246
|
requirements:
|
|
247
247
|
- - ">="
|
|
248
248
|
- !ruby/object:Gem::Version
|
|
249
|
-
version: 1.
|
|
249
|
+
version: 1.5.1
|
|
250
250
|
- !ruby/object:Gem::Dependency
|
|
251
251
|
name: legion-data
|
|
252
252
|
requirement: !ruby/object:Gem::Requirement
|
|
253
253
|
requirements:
|
|
254
254
|
- - ">="
|
|
255
255
|
- !ruby/object:Gem::Version
|
|
256
|
-
version: 1.6.
|
|
256
|
+
version: 1.6.19
|
|
257
257
|
type: :runtime
|
|
258
258
|
prerelease: false
|
|
259
259
|
version_requirements: !ruby/object:Gem::Requirement
|
|
260
260
|
requirements:
|
|
261
261
|
- - ">="
|
|
262
262
|
- !ruby/object:Gem::Version
|
|
263
|
-
version: 1.6.
|
|
263
|
+
version: 1.6.19
|
|
264
264
|
- !ruby/object:Gem::Dependency
|
|
265
265
|
name: legion-json
|
|
266
266
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -281,56 +281,56 @@ dependencies:
|
|
|
281
281
|
requirements:
|
|
282
282
|
- - ">="
|
|
283
283
|
- !ruby/object:Gem::Version
|
|
284
|
-
version: 1.
|
|
284
|
+
version: 1.5.0
|
|
285
285
|
type: :runtime
|
|
286
286
|
prerelease: false
|
|
287
287
|
version_requirements: !ruby/object:Gem::Requirement
|
|
288
288
|
requirements:
|
|
289
289
|
- - ">="
|
|
290
290
|
- !ruby/object:Gem::Version
|
|
291
|
-
version: 1.
|
|
291
|
+
version: 1.5.0
|
|
292
292
|
- !ruby/object:Gem::Dependency
|
|
293
293
|
name: legion-settings
|
|
294
294
|
requirement: !ruby/object:Gem::Requirement
|
|
295
295
|
requirements:
|
|
296
296
|
- - ">="
|
|
297
297
|
- !ruby/object:Gem::Version
|
|
298
|
-
version: 1.3.
|
|
298
|
+
version: 1.3.25
|
|
299
299
|
type: :runtime
|
|
300
300
|
prerelease: false
|
|
301
301
|
version_requirements: !ruby/object:Gem::Requirement
|
|
302
302
|
requirements:
|
|
303
303
|
- - ">="
|
|
304
304
|
- !ruby/object:Gem::Version
|
|
305
|
-
version: 1.3.
|
|
305
|
+
version: 1.3.25
|
|
306
306
|
- !ruby/object:Gem::Dependency
|
|
307
307
|
name: legion-transport
|
|
308
308
|
requirement: !ruby/object:Gem::Requirement
|
|
309
309
|
requirements:
|
|
310
310
|
- - ">="
|
|
311
311
|
- !ruby/object:Gem::Version
|
|
312
|
-
version: 1.4.
|
|
312
|
+
version: 1.4.14
|
|
313
313
|
type: :runtime
|
|
314
314
|
prerelease: false
|
|
315
315
|
version_requirements: !ruby/object:Gem::Requirement
|
|
316
316
|
requirements:
|
|
317
317
|
- - ">="
|
|
318
318
|
- !ruby/object:Gem::Version
|
|
319
|
-
version: 1.4.
|
|
319
|
+
version: 1.4.14
|
|
320
320
|
- !ruby/object:Gem::Dependency
|
|
321
321
|
name: legion-apollo
|
|
322
322
|
requirement: !ruby/object:Gem::Requirement
|
|
323
323
|
requirements:
|
|
324
324
|
- - ">="
|
|
325
325
|
- !ruby/object:Gem::Version
|
|
326
|
-
version: 0.
|
|
326
|
+
version: 0.4.0
|
|
327
327
|
type: :runtime
|
|
328
328
|
prerelease: false
|
|
329
329
|
version_requirements: !ruby/object:Gem::Requirement
|
|
330
330
|
requirements:
|
|
331
331
|
- - ">="
|
|
332
332
|
- !ruby/object:Gem::Version
|
|
333
|
-
version: 0.
|
|
333
|
+
version: 0.4.0
|
|
334
334
|
- !ruby/object:Gem::Dependency
|
|
335
335
|
name: legion-gaia
|
|
336
336
|
requirement: !ruby/object:Gem::Requirement
|