Class: Legion::Capacity::Model

Inherits:
Object
  • Object
show all
Defined in:
lib/legion/capacity/model.rb

Constant Summary collapse

DEFAULTS =
{
  tasks_per_second:   10,
  utilization_target: 0.7,
  availability_hours: 24,
  overhead_factor:    0.15
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(workers:, config: {}) ⇒ Model

Returns a new instance of Model.



13
14
15
16
# File 'lib/legion/capacity/model.rb', line 13

def initialize(workers:, config: {})
  @workers = Array(workers)
  @config = DEFAULTS.merge(config)
end

Instance Method Details

#aggregateObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/legion/capacity/model.rb', line 18

def aggregate
  active = @workers.select { |w| active_worker?(w) }
  tps = @config[:tasks_per_second]
  result = {
    total_workers:            @workers.size,
    active_workers:           active.size,
    max_throughput_tps:       active.size * tps,
    effective_throughput_tps: (active.size * tps * @config[:utilization_target]).round,
    utilization_target:       @config[:utilization_target],
    availability_hours:       @config[:availability_hours]
  }
  if defined?(Legion::Logging)
    Legion::Logging.debug "[Capacity] aggregate: total=#{result[:total_workers]} " \
                          "active=#{result[:active_workers]} effective_tps=#{result[:effective_throughput_tps]}"
  end
  result
end

#forecast(days: 30, growth_rate: 0.0) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/legion/capacity/model.rb', line 36

def forecast(days: 30, growth_rate: 0.0)
  current = aggregate
  projected = (current[:active_workers] * (1 + (growth_rate * days / 30.0))).ceil
  tps = @config[:tasks_per_second]
  result = {
    period_days:             days,
    growth_rate:             growth_rate,
    current_workers:         current[:active_workers],
    projected_workers:       projected,
    projected_max_tps:       projected * tps,
    projected_effective_tps: (projected * tps * @config[:utilization_target]).round
  }
  if defined?(Legion::Logging)
    Legion::Logging.debug "[Capacity] forecast: days=#{days} projected_workers=#{projected} projected_effective_tps=#{result[:projected_effective_tps]}"
  end
  result
end

#per_worker_statsObject



54
55
56
57
58
59
60
61
62
63
# File 'lib/legion/capacity/model.rb', line 54

def per_worker_stats
  @workers.map do |w|
    id = w[:worker_id] || w[:id] || 'unknown'
    {
      worker_id:    id,
      status:       w[:status] || w[:lifecycle_state] || 'unknown',
      capacity_tps: active_worker?(w) ? @config[:tasks_per_second] : 0
    }
  end
end