legionio 1.7.12 → 1.7.14
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 +13 -0
- data/legionio.gemspec +3 -3
- data/lib/legion/extensions/builders/actors.rb +5 -0
- data/lib/legion/extensions/catalog.rb +46 -17
- data/lib/legion/extensions.rb +38 -9
- data/lib/legion/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 86fc5b0df46813866069443960f455bfd54c68eab894e96e23c763ef1c3356e2
|
|
4
|
+
data.tar.gz: f3881012c84c5eaf039ae0c46243e9a97d5aa2ef53092a5b733a1cdeeacf9d08
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f191aabb91a76ac66d6d71890c2fcdc273f4cbd60f77768a024064b8f58386a6e2791073364c6deb93dfd95b5a8fb8485b0b26c7d0dad67eb5c3d40a1c337289
|
|
7
|
+
data.tar.gz: bb61732fe43b41f23e8bb96defb087c206d5d397bd165e3c6eef5c16f9b12e542f88de846639fb767300c5050960f0b7298d83be3d720ab80d5d11096a1008ae
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.7.14] - 2026-04-03
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Actor boot ordering: once → poll → every → loop → subscriptions, preventing timer actors from competing with AMQP channel setup
|
|
9
|
+
- Builder now respects `remote_invocable? false` and skips auto-generated subscription actors for local-only extensions
|
|
10
|
+
- Catalog exchange cached and reused instead of creating a new channel + exchange_declare per transition
|
|
11
|
+
- Catalog SQLite persists batched into a single transaction at end of boot instead of per-transition writes from concurrent threads
|
|
12
|
+
|
|
13
|
+
## [1.7.13] - 2026-04-03
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Bump legion-crypt >= 1.5.1, legion-transport >= 1.4.14, legion-cache >= 1.3.22
|
|
17
|
+
|
|
5
18
|
## [1.7.12] - 2026-04-03
|
|
6
19
|
|
|
7
20
|
### Fixed
|
data/legionio.gemspec
CHANGED
|
@@ -52,13 +52,13 @@ Gem::Specification.new do |spec|
|
|
|
52
52
|
spec.add_dependency 'thor', '>= 1.3'
|
|
53
53
|
spec.add_dependency 'tty-spinner', '~> 0.9'
|
|
54
54
|
|
|
55
|
-
spec.add_dependency 'legion-cache', '>= 1.3.
|
|
56
|
-
spec.add_dependency 'legion-crypt', '>= 1.5.
|
|
55
|
+
spec.add_dependency 'legion-cache', '>= 1.3.22'
|
|
56
|
+
spec.add_dependency 'legion-crypt', '>= 1.5.1'
|
|
57
57
|
spec.add_dependency 'legion-data', '>= 1.6.19'
|
|
58
58
|
spec.add_dependency 'legion-json', '>= 1.2.1'
|
|
59
59
|
spec.add_dependency 'legion-logging', '>= 1.5.0'
|
|
60
60
|
spec.add_dependency 'legion-settings', '>= 1.3.25'
|
|
61
|
-
spec.add_dependency 'legion-transport', '>= 1.4.
|
|
61
|
+
spec.add_dependency 'legion-transport', '>= 1.4.14'
|
|
62
62
|
|
|
63
63
|
spec.add_dependency 'legion-apollo', '>= 0.4.0'
|
|
64
64
|
spec.add_dependency 'legion-gaia', '>= 0.9.26'
|
|
@@ -37,6 +37,11 @@ module Legion
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def build_meta_actor_list
|
|
40
|
+
if lex_class.respond_to?(:remote_invocable?) && !lex_class.remote_invocable?
|
|
41
|
+
log.debug "[Actors] skipping meta actors for #{lex_class} (remote_invocable=false)"
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
|
|
40
45
|
@runners.each do |runner, attr|
|
|
41
46
|
next if @actors[runner.to_sym].is_a? Hash
|
|
42
47
|
|
|
@@ -61,6 +61,40 @@ module Legion
|
|
|
61
61
|
@warned_missing_extension_catalog = false
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
def flush_persisted_transitions
|
|
65
|
+
pending = nil
|
|
66
|
+
@pending_persists_mutex ||= Mutex.new
|
|
67
|
+
@pending_persists_mutex.synchronize do
|
|
68
|
+
return if @pending_persists.nil? || @pending_persists.empty?
|
|
69
|
+
|
|
70
|
+
pending = @pending_persists.dup
|
|
71
|
+
@pending_persists.clear
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
return unless defined?(Legion::Data::Local) &&
|
|
75
|
+
Legion::Data::Local.respond_to?(:connected?) &&
|
|
76
|
+
Legion::Data::Local.connected?
|
|
77
|
+
|
|
78
|
+
ensure_local_migration_registered!
|
|
79
|
+
return warn_missing_extension_catalog_once unless extension_catalog_table_available?
|
|
80
|
+
|
|
81
|
+
model = Legion::Data::Local.model(:extension_catalog)
|
|
82
|
+
now = Time.now
|
|
83
|
+
Legion::Data::Local.connection.transaction do
|
|
84
|
+
pending.each do |lex_name, new_state|
|
|
85
|
+
existing = model.where(lex_name: lex_name).first
|
|
86
|
+
if existing
|
|
87
|
+
existing.update(state: new_state.to_s, updated_at: now)
|
|
88
|
+
else
|
|
89
|
+
model.insert(lex_name: lex_name, state: new_state.to_s, created_at: now, updated_at: now)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
Legion::Logging.info "Catalog persisted #{pending.size} transitions" if defined?(Legion::Logging)
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
Legion::Logging.warn { "Catalog flush failed: #{e.class}: #{e.message}" } if defined?(Legion::Logging)
|
|
96
|
+
end
|
|
97
|
+
|
|
64
98
|
private
|
|
65
99
|
|
|
66
100
|
def entries
|
|
@@ -78,30 +112,25 @@ module Legion
|
|
|
78
112
|
timestamp: Time.now.to_i
|
|
79
113
|
)
|
|
80
114
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
content_type: 'application/json', persistent: true)
|
|
115
|
+
catalog_exchange.publish(payload, routing_key: "legion.catalog.#{lex_name}.#{new_state}",
|
|
116
|
+
content_type: 'application/json', persistent: true)
|
|
84
117
|
rescue StandardError => e
|
|
118
|
+
@catalog_exchange = nil
|
|
85
119
|
Legion::Logging.warn { "Catalog publish failed for #{lex_name}=#{new_state}: #{e.class}: #{e.message}" } if defined?(Legion::Logging)
|
|
86
120
|
end
|
|
87
121
|
|
|
88
|
-
def
|
|
89
|
-
return
|
|
90
|
-
Legion::Data::Local.respond_to?(:connected?) &&
|
|
91
|
-
Legion::Data::Local.connected?
|
|
122
|
+
def catalog_exchange
|
|
123
|
+
return @catalog_exchange if @catalog_exchange&.channel&.open?
|
|
92
124
|
|
|
93
|
-
|
|
94
|
-
|
|
125
|
+
@catalog_exchange = Legion::Transport::Exchange.new('legion.catalog')
|
|
126
|
+
end
|
|
95
127
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
model.insert(lex_name: lex_name, state: new_state.to_s, created_at: Time.now, updated_at: Time.now)
|
|
128
|
+
def persist_transition(lex_name, new_state)
|
|
129
|
+
@pending_persists_mutex ||= Mutex.new
|
|
130
|
+
@pending_persists_mutex.synchronize do
|
|
131
|
+
@pending_persists ||= {}
|
|
132
|
+
@pending_persists[lex_name] = new_state
|
|
102
133
|
end
|
|
103
|
-
rescue StandardError => e
|
|
104
|
-
Legion::Logging.warn { "Catalog persist failed for #{lex_name}=#{new_state}: #{e.class}: #{e.message}" } if defined?(Legion::Logging)
|
|
105
134
|
end
|
|
106
135
|
|
|
107
136
|
def extension_catalog_table_available?
|
data/lib/legion/extensions.rb
CHANGED
|
@@ -279,16 +279,18 @@ module Legion
|
|
|
279
279
|
|
|
280
280
|
Legion::Logging.info "Hooking #{@pending_actors.size} deferred actors"
|
|
281
281
|
|
|
282
|
-
|
|
283
|
-
@pending_actors.each do |actor|
|
|
284
|
-
if actor[:actor_class].ancestors.include?(Legion::Extensions::Actors::Subscription)
|
|
285
|
-
sub_actors << actor
|
|
286
|
-
else
|
|
287
|
-
hook_actor(**actor)
|
|
288
|
-
end
|
|
289
|
-
end
|
|
282
|
+
groups = group_pending_actors
|
|
290
283
|
|
|
291
|
-
|
|
284
|
+
%i[once poll every loop].each do |type|
|
|
285
|
+
next if groups[type].empty?
|
|
286
|
+
|
|
287
|
+
Legion::Logging.info "Starting #{type} actors (#{groups[type].size})"
|
|
288
|
+
groups[type].each { |actor| hook_actor(**actor) }
|
|
289
|
+
end
|
|
290
|
+
unless groups[:subscription].empty?
|
|
291
|
+
Legion::Logging.info "Starting subscription actors (#{groups[:subscription].size})"
|
|
292
|
+
hook_subscription_actors_pooled(groups[:subscription])
|
|
293
|
+
end
|
|
292
294
|
dispatch_local_actors(@local_tasks) unless @local_tasks.empty?
|
|
293
295
|
|
|
294
296
|
@pending_actors.clear
|
|
@@ -301,6 +303,33 @@ module Legion
|
|
|
301
303
|
"local:#{@local_tasks.count}"
|
|
302
304
|
)
|
|
303
305
|
@loaded_extensions&.each { |name| Catalog.transition(name, :running) }
|
|
306
|
+
Catalog.flush_persisted_transitions
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
ACTOR_TYPE_MAP = {
|
|
310
|
+
Once: :once,
|
|
311
|
+
Poll: :poll,
|
|
312
|
+
Every: :every,
|
|
313
|
+
Loop: :loop,
|
|
314
|
+
Subscription: :subscription
|
|
315
|
+
}.freeze
|
|
316
|
+
|
|
317
|
+
def group_pending_actors
|
|
318
|
+
groups = { once: [], poll: [], every: [], loop: [], subscription: [] }
|
|
319
|
+
@pending_actors.each do |actor|
|
|
320
|
+
type = resolve_actor_type(actor[:actor_class])
|
|
321
|
+
groups[type] << actor
|
|
322
|
+
end
|
|
323
|
+
groups
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def resolve_actor_type(actor_class)
|
|
327
|
+
anc = actor_class.ancestors
|
|
328
|
+
ACTOR_TYPE_MAP.each do |const, type|
|
|
329
|
+
return type if anc.include?(Legion::Extensions::Actors.const_get(const))
|
|
330
|
+
end
|
|
331
|
+
Legion::Logging.warn "Unknown actor type for #{actor_class}, defaulting to loop"
|
|
332
|
+
:loop
|
|
304
333
|
end
|
|
305
334
|
|
|
306
335
|
def hook_actor(extension:, extension_name:, actor_class:, size: 1, **opts)
|
data/lib/legion/version.rb
CHANGED
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.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -225,28 +225,28 @@ 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.5.
|
|
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.5.
|
|
249
|
+
version: 1.5.1
|
|
250
250
|
- !ruby/object:Gem::Dependency
|
|
251
251
|
name: legion-data
|
|
252
252
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -309,14 +309,14 @@ dependencies:
|
|
|
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
|