Class: ActiveMatrix::AgentRegistry

Inherits:
Object
  • Object
show all
Includes:
Logging, Singleton
Defined in:
lib/active_matrix/agent_registry.rb

Overview

Thread-safe registry for managing running bot agents

Instance Method Summary collapse

Methods included from Logging

included, #logger, #logger=

Constructor Details

#initializeAgentRegistry

Returns a new instance of AgentRegistry.



12
13
14
# File 'lib/active_matrix/agent_registry.rb', line 12

def initialize
  @agents = Concurrent::Hash.new
end

Instance Method Details

#allObject

Get all running agents



54
55
56
# File 'lib/active_matrix/agent_registry.rb', line 54

def all
  @agents.values
end

#all_instancesObject

Get all bot instances



64
65
66
# File 'lib/active_matrix/agent_registry.rb', line 64

def all_instances
  @agents.values.pluck(:instance)
end

#all_recordsObject

Get all agent records



59
60
61
# File 'lib/active_matrix/agent_registry.rb', line 59

def all_records
  @agents.values.pluck(:record)
end

#broadcastObject

Broadcast to all agents



90
91
92
93
94
95
96
# File 'lib/active_matrix/agent_registry.rb', line 90

def broadcast
  all_instances.each do |instance|
    yield instance
  rescue StandardError => e
    logger.error "Error broadcasting to agent: #{e.message}"
  end
end

#broadcast_to(selector) ⇒ Object

Broadcast to specific agents



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/active_matrix/agent_registry.rb', line 99

def broadcast_to(selector)
  agents = case selector
           when Symbol
             by_state(selector)
           when String
             by_name_pattern(selector)
           when Class
             by_class(selector)
           when Proc
             @agents.values.select { |entry| selector.call(entry[:record]) }
           else
             []
           end

  agents.each do |entry|
    yield entry[:instance]
  rescue StandardError => e
    logger.error "Error broadcasting to agent #{entry[:record].name}: #{e.message}"
  end
end

#by_class(bot_class) ⇒ Object

Get agents by bot class



79
80
81
82
# File 'lib/active_matrix/agent_registry.rb', line 79

def by_class(bot_class)
  class_name = bot_class.is_a?(Class) ? bot_class.name : bot_class.to_s
  @agents.values.select { |entry| entry[:record].bot_class == class_name }
end

#by_homeserver(homeserver) ⇒ Object

Get agents by homeserver



85
86
87
# File 'lib/active_matrix/agent_registry.rb', line 85

def by_homeserver(homeserver)
  @agents.values.select { |entry| entry[:record].homeserver == homeserver }
end

#by_state(state) ⇒ Object

Get agents by state



74
75
76
# File 'lib/active_matrix/agent_registry.rb', line 74

def by_state(state)
  @agents.values.select { |entry| entry[:record].state == state.to_s }
end

#clear!Object

Clear all agents (used for testing)



126
127
128
# File 'lib/active_matrix/agent_registry.rb', line 126

def clear!
  @agents.clear
end

#countObject

Get count of running agents



121
122
123
# File 'lib/active_matrix/agent_registry.rb', line 121

def count
  @agents.size
end

#find_eachObject

Iterate through all agents



145
146
147
# File 'lib/active_matrix/agent_registry.rb', line 145

def find_each(&)
  @agents.values.each(&)
end

#get(agent_id) ⇒ Object

Get a running agent by ID



44
45
46
# File 'lib/active_matrix/agent_registry.rb', line 44

def get(agent_id)
  @agents[agent_id]
end

#get_by_name(name) ⇒ Object

Get agent by name



49
50
51
# File 'lib/active_matrix/agent_registry.rb', line 49

def get_by_name(name)
  @agents.values.find { |entry| entry[:record].name == name }
end

#health_statusObject

Get health status of all agents



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/active_matrix/agent_registry.rb', line 131

def health_status
  @agents.map do |id, entry|
    {
      id: id,
      name: entry[:record].name,
      state: entry[:record].state,
      task_alive: entry[:task]&.alive?,
      uptime: Time.current - entry[:started_at],
      last_active: entry[:record].last_active_at
    }
  end
end

#register(agent_record, bot_instance) ⇒ Object

Register a running agent



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/active_matrix/agent_registry.rb', line 17

def register(agent_record, bot_instance)
  raise AgentAlreadyRunningError, "Agent #{agent_record.name} is already running" if @agents.key?(agent_record.id)

  @agents[agent_record.id] = {
    record: agent_record,
    instance: bot_instance,
    task: nil,
    started_at: Time.current
  }

  logger.info "Registered agent: #{agent_record.name} (#{agent_record.id})"
end

#register_task(agent_record, task) ⇒ Object

Register an async task for an agent



31
32
33
34
# File 'lib/active_matrix/agent_registry.rb', line 31

def register_task(agent_record, task)
  entry = @agents[agent_record.id]
  entry[:task] = task if entry
end

#running?(agent_record) ⇒ Boolean

Check if an agent is running

Returns:

  • (Boolean)


69
70
71
# File 'lib/active_matrix/agent_registry.rb', line 69

def running?(agent_record)
  @agents.key?(agent_record.id)
end

#unregister(agent_record) ⇒ Object

Unregister an agent



37
38
39
40
41
# File 'lib/active_matrix/agent_registry.rb', line 37

def unregister(agent_record)
  entry = @agents.delete(agent_record.id)
  logger.info "Unregistered agent: #{agent_record.name} (#{agent_record.id})" if entry
  entry
end