Module: RcrewAI::Rails::Observation::Rollup

Defined in:
lib/rcrewai/rails/observation/rollup.rb

Overview

Denormalized totals on Execution. The span tree is the source of truth; these are a cache so cost/performance views never walk it.

Counters use atomic SQL updates because agents run concurrently.

Class Method Summary collapse

Class Method Details

.guardObject



49
50
51
52
53
54
55
56
# File 'lib/rcrewai/rails/observation/rollup.rb', line 49

def guard
  yield
rescue StandardError => e
  if defined?(::Rails) && ::Rails.respond_to?(:logger) && ::Rails.logger
    ::Rails.logger.warn("[rcrewai-rails] rollup failed: #{e.class}: #{e.message}")
  end
  nil
end

.rebuild!(execution) ⇒ Object

Recomputes from the spans themselves. The repair path when buffered writes are lost to a crash.



33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rcrewai/rails/observation/rollup.rb', line 33

def rebuild!(execution)
  guard do
    spans = Span.where(execution_id: execution.id)
    scope(execution).update_all(
      total_tokens: spans.sum(:total_tokens),
      total_cost_usd: spans.sum(:cost_usd),
      span_count: spans.count,
      error_count: spans.errored.count
    )
  end
end

.record_error(execution) ⇒ Object



27
28
29
# File 'lib/rcrewai/rails/observation/rollup.rb', line 27

def record_error(execution)
  guard { scope(execution).update_all("error_count = COALESCE(error_count, 0) + 1") }
end

.record_span(execution) ⇒ Object



23
24
25
# File 'lib/rcrewai/rails/observation/rollup.rb', line 23

def record_span(execution)
  guard { scope(execution).update_all("span_count = COALESCE(span_count, 0) + 1") }
end

.record_usage(execution, tokens:, cost:) ⇒ Object



13
14
15
16
17
18
19
20
21
# File 'lib/rcrewai/rails/observation/rollup.rb', line 13

def record_usage(execution, tokens:, cost:)
  guard do
    scope(execution).update_all([
      "total_tokens = COALESCE(total_tokens, 0) + ?, " \
      "total_cost_usd = COALESCE(total_cost_usd, 0) + ?",
      tokens.to_i, cost.to_f
    ])
  end
end

.scope(execution) ⇒ Object



45
46
47
# File 'lib/rcrewai/rails/observation/rollup.rb', line 45

def scope(execution)
  Execution.where(id: execution.id)
end