Class: LittleGhost::AgentInterruptions
- Inherits:
-
Object
- Object
- LittleGhost::AgentInterruptions
- Defined in:
- lib/little_ghost/agent_interruptions.rb
Overview
:nodoc: all
Defined Under Namespace
Classes: Batch, Response, Ticket
Constant Summary collapse
- MAX_BATCH_SIZE =
100- MAX_INTERRUPTION_COUNT =
1_000
Instance Attribute Summary collapse
-
#operation_id ⇒ Object
readonly
Returns the value of attribute operation_id.
-
#target_operation_id ⇒ Object
readonly
Returns the value of attribute target_operation_id.
Instance Method Summary collapse
- #bind(operation_id, target_operation_id:) ⇒ Object
- #close(error) ⇒ Object
- #deliver ⇒ Object
- #enqueue(message, id: SecureRandom.uuid, batch_key: nil, metadata: {}) ⇒ Object
- #finish ⇒ Object
-
#initialize ⇒ AgentInterruptions
constructor
A new instance of AgentInterruptions.
- #pending? ⇒ Boolean
- #release(ticket, withdraw: false) ⇒ Object
- #resolve(batch, response) ⇒ Object
Constructor Details
#initialize ⇒ AgentInterruptions
Returns a new instance of AgentInterruptions.
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/little_ghost/agent_interruptions.rb', line 82 def initialize @mutex = Mutex.new @queue = [] @tickets_by_id = {} @waiters = Hash.new(0) @delivered = nil @closed_error = nil @operation_id = nil @target_operation_id = nil end |
Instance Attribute Details
#operation_id ⇒ Object (readonly)
Returns the value of attribute operation_id.
80 81 82 |
# File 'lib/little_ghost/agent_interruptions.rb', line 80 def operation_id @operation_id end |
#target_operation_id ⇒ Object (readonly)
Returns the value of attribute target_operation_id.
80 81 82 |
# File 'lib/little_ghost/agent_interruptions.rb', line 80 def target_operation_id @target_operation_id end |
Instance Method Details
#bind(operation_id, target_operation_id:) ⇒ Object
93 94 95 96 97 98 |
# File 'lib/little_ghost/agent_interruptions.rb', line 93 def bind(operation_id, target_operation_id:) @mutex.synchronize do @operation_id = operation_id @target_operation_id = target_operation_id || operation_id end end |
#close(error) ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/little_ghost/agent_interruptions.rb', line 184 def close(error) tickets = @mutex.synchronize do return if @closed_error @closed_error = error values = [*@delivered&.tickets, *@queue].compact @delivered = nil @queue.clear values end tickets.each { |ticket| ticket.reject(error) } end |
#deliver ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/little_ghost/agent_interruptions.rb', line 134 def deliver @mutex.synchronize do return if @delivered || @queue.empty? batch_key = @queue.first.batch_key tickets = [] tickets << @queue.shift if batch_key while tickets.length < MAX_BATCH_SIZE && @queue.first&.batch_key == batch_key tickets << @queue.shift end end @delivered = Batch.new(tickets: tickets.freeze) end end |
#enqueue(message, id: SecureRandom.uuid, batch_key: nil, metadata: {}) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/little_ghost/agent_interruptions.rb', line 100 def enqueue(, id: SecureRandom.uuid, batch_key: nil, metadata: {}) id = String(id) raise ArgumentError, "interruption_id cannot be empty" if id.empty? batch_key = String(batch_key) unless batch_key.nil? = .to_h @mutex.synchronize do raise @closed_error if @closed_error existing = @tickets_by_id[id] if existing unless existing..to_h == .to_h && existing.batch_key == batch_key && existing. == raise ArgumentError, "interruption_id has already been used with different input" end @waiters[existing] += 1 return existing end if @tickets_by_id.length >= MAX_INTERRUPTION_COUNT raise AgentInterruptError, "Agent interruption capacity reached" end ticket = Ticket.new(, id: id.freeze, batch_key: batch_key&.freeze, metadata:) @tickets_by_id[id] = ticket @waiters[ticket] = 1 @queue << ticket ticket end rescue TypeError, NoMethodError raise ArgumentError, "interruption_id, batch_key, and metadata are invalid" end |
#finish ⇒ Object
164 165 166 167 168 169 170 171 172 |
# File 'lib/little_ghost/agent_interruptions.rb', line 164 def finish @mutex.synchronize do return true if @closed_error return false if @delivered || !@queue.empty? @closed_error = AgentInterruptError.new("Agent is not currently running") true end end |
#pending? ⇒ Boolean
160 161 162 |
# File 'lib/little_ghost/agent_interruptions.rb', line 160 def pending? @mutex.synchronize { !@queue.empty? } end |
#release(ticket, withdraw: false) ⇒ Object
174 175 176 177 178 179 180 181 182 |
# File 'lib/little_ghost/agent_interruptions.rb', line 174 def release(ticket, withdraw: false) @mutex.synchronize do @waiters[ticket] -= 1 return unless withdraw && @waiters[ticket] <= 0 && @queue.delete(ticket) @tickets_by_id.delete(ticket.id) @waiters.delete(ticket) end end |
#resolve(batch, response) ⇒ Object
150 151 152 153 154 155 156 157 158 |
# File 'lib/little_ghost/agent_interruptions.rb', line 150 def resolve(batch, response) tickets = @mutex.synchronize do return unless batch && @delivered.equal?(batch) @delivered = nil batch.tickets end tickets.each { |ticket| ticket.resolve(response) } end |