Module: RcrewAI::Rails::Observation::Pruner

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

Overview

Removes spans past the retention window. Without this the span table becomes the largest in the host application's database.

Class Method Summary collapse

Class Method Details

.prune!(older_than_days: nil, batch_size: 1_000) ⇒ Object

Returns the number of spans removed. Deletes in batches so a large backlog does not hold one enormous transaction open.

Retention is applied per EXECUTION, not per span. Deleting spans by their own age fractures mixed-age traces: a surviving child of a deleted parent keeps a dangling parent_span_id, and because it is neither a root nor reachable from any parent it disappears from the trace view entirely. A trace is kept or dropped whole.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/rcrewai/rails/observation/pruner.rb', line 19

def prune!(older_than_days: nil, batch_size: 1_000)
  days = older_than_days || RcrewAI::Rails.config.observation_retention_days
  cutoff = days.to_i.days.ago
  removed = 0

  loop do
    execution_ids = stale_execution_ids(cutoff, batch_size)
    break if execution_ids.empty?

    span_ids = Span.where(execution_id: execution_ids).pluck(:id)
    SpanEvent.where(span_id: span_ids).delete_all
    removed += Span.where(id: span_ids).delete_all
  end

  removed
end

.stale_execution_ids(cutoff, batch_size) ⇒ Object

Executions whose newest span predates the cutoff. Grouping by execution means a long-running trace straddling the boundary is retained until all of it has aged out.



39
40
41
42
43
44
# File 'lib/rcrewai/rails/observation/pruner.rb', line 39

def stale_execution_ids(cutoff, batch_size)
  Span.group(:execution_id)
      .having(Span.arel_table[:created_at].maximum.lt(cutoff))
      .limit(batch_size)
      .pluck(:execution_id)
end