lex-mesh 0.1.1 → 0.2.3
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/Gemfile +0 -2
- data/lex-mesh.gemspec +0 -1
- data/lib/legion/extensions/mesh/actors/pending_expiry.rb +37 -0
- data/lib/legion/extensions/mesh/actors/preference_listener.rb +44 -0
- data/lib/legion/extensions/mesh/actors/silence_watchdog.rb +37 -0
- data/lib/legion/extensions/mesh/client.rb +7 -2
- data/lib/legion/extensions/mesh/helpers/pending_requests.rb +57 -0
- data/lib/legion/extensions/mesh/helpers/registry.rb +12 -0
- data/lib/legion/extensions/mesh/runners/mesh.rb +20 -0
- data/lib/legion/extensions/mesh/runners/preferences.rb +120 -0
- data/lib/legion/extensions/mesh/transport/messages/mesh_departure.rb +34 -0
- data/lib/legion/extensions/mesh/transport/messages/preference_query.rb +34 -0
- data/lib/legion/extensions/mesh/transport/messages/preference_response.rb +34 -0
- data/lib/legion/extensions/mesh/transport/queues/preference.rb +27 -0
- data/lib/legion/extensions/mesh/version.rb +1 -1
- data/lib/legion/extensions/mesh.rb +9 -0
- data/spec/legion/extensions/mesh/actors/pending_expiry_spec.rb +57 -0
- data/spec/legion/extensions/mesh/actors/preference_listener_spec.rb +87 -0
- data/spec/legion/extensions/mesh/actors/silence_watchdog_spec.rb +55 -0
- data/spec/legion/extensions/mesh/client_spec.rb +40 -1
- data/spec/legion/extensions/mesh/helpers/pending_requests_spec.rb +80 -0
- data/spec/legion/extensions/mesh/helpers/registry_spec.rb +41 -0
- data/spec/legion/extensions/mesh/runners/mesh_spec.rb +25 -0
- data/spec/legion/extensions/mesh/runners/preferences_spec.rb +164 -0
- data/spec/legion/extensions/mesh/transport/messages/mesh_departure_spec.rb +81 -0
- data/spec/legion/extensions/mesh/transport/messages/preference_query_spec.rb +85 -0
- data/spec/legion/extensions/mesh/transport/messages/preference_response_spec.rb +85 -0
- data/spec/legion/extensions/mesh/transport/queues/preference_spec.rb +61 -0
- metadata +20 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75ab8e1dbc78d725a92257640520bfda3f3acb36ae1dc1f1315cc7e8453ca467
|
|
4
|
+
data.tar.gz: 269027a72a18770e8bf0338fa7c2941bc354546ffc6157bd2533fc258b054baf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78afa9c435f105a2c18b107d14de0c6d4b9c8850c5181ce394aafe46613c70dedccb24b5b19dbf5ee71f2fa71657905e656d2d4eb916f3429446f0c61398a46d
|
|
7
|
+
data.tar.gz: 766eb42fd99abaa287af0cd1f48b8daba505f9e4d20dccb927e748cb9734460839915ba2e8513aa8df5bf28817f032f230e08e5bf775f3330d9e4f34d48f47db
|
data/Gemfile
CHANGED
data/lex-mesh.gemspec
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/every'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Mesh
|
|
8
|
+
module Actor
|
|
9
|
+
class PendingExpiry < Legion::Extensions::Actors::Every
|
|
10
|
+
def runner_class
|
|
11
|
+
Legion::Extensions::Mesh::Runners::Preferences
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def runner_function
|
|
15
|
+
'expire_pending_requests'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def time
|
|
19
|
+
30
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def use_runner?
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def check_subtask?
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generate_task?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/subscription'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Mesh
|
|
8
|
+
module Actor
|
|
9
|
+
class PreferenceListener < Legion::Extensions::Actors::Subscription
|
|
10
|
+
def runner_class
|
|
11
|
+
Legion::Extensions::Mesh::Runners::Preferences
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def runner_function
|
|
15
|
+
'dispatch_preference_message'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def check_subtask?
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def generate_task?
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def use_runner?
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def queue
|
|
31
|
+
Legion::Extensions::Mesh::Transport::Queues::Preference
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def enabled?
|
|
35
|
+
defined?(Legion::Extensions::Mesh::Runners::Preferences) &&
|
|
36
|
+
defined?(Legion::Transport)
|
|
37
|
+
rescue StandardError
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/every'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Mesh
|
|
8
|
+
module Actor
|
|
9
|
+
class SilenceWatchdog < Legion::Extensions::Actors::Every
|
|
10
|
+
def runner_class
|
|
11
|
+
Legion::Extensions::Mesh::Runners::Mesh
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def runner_function
|
|
15
|
+
'expire_silent_agents'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def time
|
|
19
|
+
15
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def use_runner?
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def check_subtask?
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generate_task?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'legion/extensions/mesh/runners/mesh'
|
|
4
|
+
require 'legion/extensions/mesh/runners/preferences'
|
|
5
|
+
require 'legion/extensions/mesh/helpers/preference_profile'
|
|
6
|
+
require 'legion/extensions/mesh/helpers/pending_requests'
|
|
3
7
|
require 'legion/extensions/mesh/helpers/topology'
|
|
4
8
|
require 'legion/extensions/mesh/helpers/registry'
|
|
5
|
-
require 'legion/extensions/mesh/runners/mesh'
|
|
6
9
|
|
|
7
10
|
module Legion
|
|
8
11
|
module Extensions
|
|
9
12
|
module Mesh
|
|
10
13
|
class Client
|
|
11
14
|
include Runners::Mesh
|
|
15
|
+
include Runners::Preferences
|
|
12
16
|
|
|
13
|
-
def initialize(**)
|
|
17
|
+
def initialize(**opts)
|
|
18
|
+
@opts = opts
|
|
14
19
|
@mesh_registry = Helpers::Registry.new
|
|
15
20
|
end
|
|
16
21
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Mesh
|
|
6
|
+
module Helpers
|
|
7
|
+
class PendingRequests
|
|
8
|
+
def initialize(default_ttl: 5)
|
|
9
|
+
@default_ttl = default_ttl
|
|
10
|
+
@requests = {}
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def register(correlation_id:, callback:, ttl: nil)
|
|
15
|
+
@mutex.synchronize do
|
|
16
|
+
@requests[correlation_id] = {
|
|
17
|
+
callback: callback,
|
|
18
|
+
registered_at: Time.now,
|
|
19
|
+
ttl: ttl || @default_ttl
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def resolve(correlation_id:, result:) # rubocop:disable Naming/PredicateMethod
|
|
25
|
+
entry = @mutex.synchronize { @requests.delete(correlation_id) }
|
|
26
|
+
return false unless entry
|
|
27
|
+
|
|
28
|
+
entry[:callback]&.call(result)
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def pending?(correlation_id)
|
|
33
|
+
@mutex.synchronize { @requests.key?(correlation_id) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def pending_count
|
|
37
|
+
@mutex.synchronize { @requests.size }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def expire
|
|
41
|
+
now = Time.now
|
|
42
|
+
expired = []
|
|
43
|
+
@mutex.synchronize do
|
|
44
|
+
@requests.each do |id, entry|
|
|
45
|
+
next unless now - entry[:registered_at] >= entry[:ttl]
|
|
46
|
+
|
|
47
|
+
expired << id
|
|
48
|
+
end
|
|
49
|
+
expired.each { |id| @requests.delete(id) }
|
|
50
|
+
end
|
|
51
|
+
expired
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -65,6 +65,18 @@ module Legion
|
|
|
65
65
|
msg
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
def expire_silent_agents(timeout: Topology::MESH_SILENCE_TIMEOUT)
|
|
69
|
+
cutoff = Time.now.utc - timeout
|
|
70
|
+
expired = []
|
|
71
|
+
@agents.each_value do |agent|
|
|
72
|
+
next unless agent[:status] == :online && agent[:last_seen] < cutoff
|
|
73
|
+
|
|
74
|
+
agent[:status] = :offline
|
|
75
|
+
expired << agent[:agent_id]
|
|
76
|
+
end
|
|
77
|
+
expired
|
|
78
|
+
end
|
|
79
|
+
|
|
68
80
|
def online_agents
|
|
69
81
|
@agents.values.select { |a| a[:status] == :online }
|
|
70
82
|
end
|
|
@@ -18,6 +18,7 @@ module Legion
|
|
|
18
18
|
result = mesh_registry.unregister_agent(agent_id)
|
|
19
19
|
if result
|
|
20
20
|
Legion::Logging.info "[mesh] unregistered: agent=#{agent_id}"
|
|
21
|
+
publish_mesh_departure(agent_id: agent_id, capabilities: result[:capabilities] || [])
|
|
21
22
|
{ unregistered: true }
|
|
22
23
|
else
|
|
23
24
|
Legion::Logging.debug "[mesh] unregister failed: agent=#{agent_id} not found"
|
|
@@ -55,8 +56,27 @@ module Legion
|
|
|
55
56
|
{ total: total, online: online.size, message_count: msgs }
|
|
56
57
|
end
|
|
57
58
|
|
|
59
|
+
def expire_silent_agents(**)
|
|
60
|
+
expired = mesh_registry.expire_silent_agents
|
|
61
|
+
expired.each do |agent_id|
|
|
62
|
+
Legion::Logging.info "[mesh] expired silent agent: #{agent_id}"
|
|
63
|
+
end
|
|
64
|
+
{ success: true, expired: expired, count: expired.size }
|
|
65
|
+
end
|
|
66
|
+
|
|
58
67
|
private
|
|
59
68
|
|
|
69
|
+
def publish_mesh_departure(agent_id:, capabilities:)
|
|
70
|
+
return unless defined?(Legion::Extensions::Mesh::Transport::Messages::MeshDeparture)
|
|
71
|
+
|
|
72
|
+
Legion::Extensions::Mesh::Transport::Messages::MeshDeparture.new(
|
|
73
|
+
agent_id: agent_id, capabilities: capabilities
|
|
74
|
+
).publish
|
|
75
|
+
Legion::Logging.debug "[mesh] departure signal published: agent=#{agent_id}"
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
Legion::Logging.warn "[mesh] failed to publish departure signal: #{e.message}"
|
|
78
|
+
end
|
|
79
|
+
|
|
60
80
|
def mesh_registry
|
|
61
81
|
@mesh_registry ||= Helpers::Registry.new
|
|
62
82
|
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Mesh
|
|
8
|
+
module Runners
|
|
9
|
+
module Preferences
|
|
10
|
+
def query_preferences(target_agent_id:, domains: nil, callback: nil, ttl: 5, **)
|
|
11
|
+
default_profile = Helpers::PreferenceProfile.resolve(owner_id: target_agent_id)
|
|
12
|
+
|
|
13
|
+
return { success: true, source: :local_default, profile: default_profile } unless transport_available?
|
|
14
|
+
|
|
15
|
+
correlation_id = SecureRandom.uuid
|
|
16
|
+
cb = callback || default_preference_callback(target_agent_id: target_agent_id)
|
|
17
|
+
pending_requests.register(correlation_id: correlation_id, callback: cb, ttl: ttl)
|
|
18
|
+
|
|
19
|
+
publish_preference_query(
|
|
20
|
+
target_agent_id: target_agent_id,
|
|
21
|
+
correlation_id: correlation_id,
|
|
22
|
+
domains: domains
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
{ success: true, source: :pending, correlation_id: correlation_id, profile: default_profile }
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
{ success: true, source: :local_default, profile: default_profile, error: e.message }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def handle_preference_query(**)
|
|
31
|
+
owner_id = local_agent_id
|
|
32
|
+
profile = Helpers::PreferenceProfile.resolve(owner_id: owner_id)
|
|
33
|
+
|
|
34
|
+
{ success: true, profile: profile, responding_agent_id: local_agent_id }
|
|
35
|
+
rescue StandardError => e
|
|
36
|
+
{ success: false, error: e.message }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def handle_preference_response(correlation_id:, profile:, **)
|
|
40
|
+
resolved = pending_requests.resolve(correlation_id: correlation_id, result: profile)
|
|
41
|
+
{ resolved: resolved }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def expire_pending_requests(**)
|
|
45
|
+
expired = pending_requests.expire
|
|
46
|
+
{ expired: expired.size, correlation_ids: expired }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def dispatch_preference_message(type: nil, **msg)
|
|
50
|
+
case type
|
|
51
|
+
when 'preference_query'
|
|
52
|
+
profile = handle_preference_query(**msg)
|
|
53
|
+
publish_preference_response(msg, profile) if profile[:success]
|
|
54
|
+
profile
|
|
55
|
+
when 'preference_response'
|
|
56
|
+
handle_preference_response(
|
|
57
|
+
correlation_id: msg[:correlation_id],
|
|
58
|
+
profile: msg[:profile] || {}
|
|
59
|
+
)
|
|
60
|
+
else
|
|
61
|
+
{ success: false, error: "unknown preference message type: #{type}" }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def pending_requests
|
|
68
|
+
@pending_requests ||= Helpers::PendingRequests.new
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def transport_available?
|
|
72
|
+
defined?(Legion::Transport::Connection) &&
|
|
73
|
+
Legion::Transport::Connection.respond_to?(:session)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def local_agent_id
|
|
77
|
+
if defined?(Legion::Settings)
|
|
78
|
+
Legion::Settings['client']['name']
|
|
79
|
+
else
|
|
80
|
+
'unknown'
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def publish_preference_response(msg, profile)
|
|
85
|
+
return unless transport_available?
|
|
86
|
+
|
|
87
|
+
Transport::Messages::PreferenceResponse.new(
|
|
88
|
+
target_agent_id: msg[:requesting_agent_id],
|
|
89
|
+
responding_agent_id: local_agent_id,
|
|
90
|
+
profile: profile[:profile],
|
|
91
|
+
correlation_id: msg[:correlation_id]
|
|
92
|
+
).publish
|
|
93
|
+
rescue StandardError => e
|
|
94
|
+
log_debug("[mesh] failed to publish preference response: #{e.message}")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def publish_preference_query(target_agent_id:, correlation_id:, domains:)
|
|
98
|
+
Transport::Messages::PreferenceQuery.new(
|
|
99
|
+
target_agent_id: target_agent_id,
|
|
100
|
+
requesting_agent_id: local_agent_id,
|
|
101
|
+
domains: domains || [],
|
|
102
|
+
reply_to: "agent.#{local_agent_id}.preferences",
|
|
103
|
+
correlation_id: correlation_id
|
|
104
|
+
).publish
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def default_preference_callback(target_agent_id:)
|
|
108
|
+
lambda do |profile|
|
|
109
|
+
log_debug("[mesh] received preferences for #{target_agent_id}: #{profile.keys.join(', ')}")
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def log_debug(msg)
|
|
114
|
+
Legion::Logging.debug(msg) if defined?(Legion::Logging)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Mesh
|
|
6
|
+
module Transport
|
|
7
|
+
module Messages
|
|
8
|
+
class MeshDeparture < Legion::Transport::Message
|
|
9
|
+
def exchange
|
|
10
|
+
Legion::Transport::Exchanges::Node
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def routing_key
|
|
14
|
+
'mesh.departure'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def message
|
|
18
|
+
{
|
|
19
|
+
type: 'mesh_departure',
|
|
20
|
+
agent_id: @options[:agent_id],
|
|
21
|
+
capabilities: @options[:capabilities] || [],
|
|
22
|
+
departed_at: Time.now.to_s
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def type
|
|
27
|
+
'mesh_departure'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Mesh
|
|
6
|
+
module Transport
|
|
7
|
+
module Messages
|
|
8
|
+
class PreferenceQuery < Legion::Transport::Message
|
|
9
|
+
def exchange
|
|
10
|
+
Legion::Transport::Exchanges::Agent
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def routing_key
|
|
14
|
+
"agent.#{@options[:target_agent_id]}.preferences"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def message
|
|
18
|
+
{
|
|
19
|
+
type: 'preference_query',
|
|
20
|
+
requesting_agent_id: @options[:requesting_agent_id],
|
|
21
|
+
domains: @options[:domains] || [],
|
|
22
|
+
requested_at: Time.now.to_s
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def type
|
|
27
|
+
'preference_query'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Mesh
|
|
6
|
+
module Transport
|
|
7
|
+
module Messages
|
|
8
|
+
class PreferenceResponse < Legion::Transport::Message
|
|
9
|
+
def exchange
|
|
10
|
+
Legion::Transport::Exchanges::Agent
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def routing_key
|
|
14
|
+
"agent.#{@options[:target_agent_id]}.preferences"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def message
|
|
18
|
+
{
|
|
19
|
+
type: 'preference_response',
|
|
20
|
+
responding_agent_id: @options[:responding_agent_id],
|
|
21
|
+
profile: @options[:profile] || {},
|
|
22
|
+
responded_at: Time.now.to_s
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def type
|
|
27
|
+
'preference_response'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Mesh
|
|
6
|
+
module Transport
|
|
7
|
+
module Queues
|
|
8
|
+
class Preference < Legion::Transport::Queues::Agent
|
|
9
|
+
def initialize(agent_id: nil, **)
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def queue_name
|
|
14
|
+
agent = @agent_id || Legion::Settings['client']['name']
|
|
15
|
+
"agent.#{agent}.preferences"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def bind_routing_key
|
|
19
|
+
agent = @agent_id || Legion::Settings['client']['name']
|
|
20
|
+
"agent.#{agent}.preferences"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -4,7 +4,16 @@ require 'legion/extensions/mesh/version'
|
|
|
4
4
|
require 'legion/extensions/mesh/helpers/topology'
|
|
5
5
|
require 'legion/extensions/mesh/helpers/registry'
|
|
6
6
|
require 'legion/extensions/mesh/helpers/preference_profile'
|
|
7
|
+
require 'legion/extensions/mesh/helpers/pending_requests'
|
|
7
8
|
require 'legion/extensions/mesh/runners/mesh'
|
|
9
|
+
require 'legion/extensions/mesh/runners/preferences'
|
|
10
|
+
|
|
11
|
+
if defined?(Legion::Transport)
|
|
12
|
+
require 'legion/extensions/mesh/transport/messages/preference_query'
|
|
13
|
+
require 'legion/extensions/mesh/transport/messages/preference_response'
|
|
14
|
+
require 'legion/extensions/mesh/transport/messages/mesh_departure'
|
|
15
|
+
require 'legion/extensions/mesh/transport/queues/preference'
|
|
16
|
+
end
|
|
8
17
|
|
|
9
18
|
module Legion
|
|
10
19
|
module Extensions
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Stub the framework actor base class
|
|
4
|
+
unless defined?(Legion::Extensions::Actors::Every)
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Actors
|
|
8
|
+
class Every # rubocop:disable Lint/EmptyClass
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
$LOADED_FEATURES << 'legion/extensions/actors/every' unless $LOADED_FEATURES.include?('legion/extensions/actors/every')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
require 'legion/extensions/mesh/actors/pending_expiry'
|
|
18
|
+
|
|
19
|
+
RSpec.describe Legion::Extensions::Mesh::Actor::PendingExpiry do
|
|
20
|
+
subject(:actor) { described_class.new }
|
|
21
|
+
|
|
22
|
+
describe '#runner_class' do
|
|
23
|
+
it 'returns the Preferences runner module' do
|
|
24
|
+
expect(actor.runner_class).to eq(Legion::Extensions::Mesh::Runners::Preferences)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#runner_function' do
|
|
29
|
+
it 'returns expire_pending_requests' do
|
|
30
|
+
expect(actor.runner_function).to eq('expire_pending_requests')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#time' do
|
|
35
|
+
it 'returns 30' do
|
|
36
|
+
expect(actor.time).to eq(30)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe '#use_runner?' do
|
|
41
|
+
it 'returns false' do
|
|
42
|
+
expect(actor.use_runner?).to be false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe '#check_subtask?' do
|
|
47
|
+
it 'returns false' do
|
|
48
|
+
expect(actor.check_subtask?).to be false
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#generate_task?' do
|
|
53
|
+
it 'returns false' do
|
|
54
|
+
expect(actor.generate_task?).to be false
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|