• /
  • EnglishEspañolFrançais日本語한국어Português
  • EntrarComeçar agora

Managing long-running transactions

The Ruby agent isn't designed to trace transactions that run for a very long time or that never end. This guide explains why that can cause memory to grow and provides strategies for working around it.

Problem

Your application's memory usage grows continuously, and it correlates with one or more transactions that stay open for a long time. This is most common with:

  • A background job or worker that stays in one transaction for a long time, such as processing a large batch or issuing many database queries or external calls
  • A thread that lives for the lifetime of the process, which the agent treats as one continuously running transaction
  • Any transaction that runs much longer than usual, or never finishes

Why this happens

For every traced unit of work in a transaction, the agent creates a segment so it can build a transaction trace and calculate exclusive time for each segment's parent. The transaction_tracer.limit_segments setting (default 4000) caps how many of those segments get added to the transaction trace.

However, even after that limit is reached, the agent continues creating a segment for each additional unit of work and tracking its start and end time, in order to keep parent segments' exclusive time calculations accurate. For a transaction that keeps running, this timing data keeps accumulating for as long as the transaction stays open. This means that memory tied to that transaction won't get released until the transaction finishes, which for a long-running or never-ending transaction, can be a very long time.

Solutions

Cap memory growth with configuration options

None of the options below make a transaction shorter, but they can limit how much data the agent keeps around while a transaction stays open.

Use custom instrumentation

  • Break up transactions. For long transactions, you may consider using custom instrumentation to instrument each unit of work inside a transaction as its own short transaction. Each transaction's segment data is recorded and released as soon as that transaction finishes, rather than accumulating for the entire duration of one transaction. Using NewRelic::Agent::Tracer.in_transaction:

    require 'new_relic/agent/tracer'
    def process_large_batch(items)
    items.each do |item|
    NewRelic::Agent::Tracer.in_transaction(partial_name: 'Custom/process_item', category: :task) do
    process_item(item)
    end
    end
    end

    This keeps metrics, traces, and error reporting working as expected, while replacing one continuously growing transaction with many short-lived ones.

  • Stop segment accumulation entirely for a job's duration. Wrapping the body of a long-running job in NewRelic::Agent.disable_all_tracing stops the accumulation described above outright, because work done inside the block is never attached to the transaction:

    def perform(*args)
    NewRelic::Agent.disable_all_tracing do
    do_the_long_running_work(*args)
    end
    end

    The trade-off is losing all instrumentation detail for anything inside the block. Whether that trade-off is worthwhile depends on how much visibility into the job you need.

Instrument long-running work with OpenTelemetry

For code that's not a good fit for the agent's transaction model even after applying the options above, consider instrumenting that portion of code with the OpenTelemetry Ruby SDK and exporting it via OTLP to New Relic. Instead of having the same long-lived transaction object holding data for a job's full duration, OpenTelemetry exports each span as soon as it finishes.

Importante

This is different from the Ruby agent's OpenTelemetry API support. That feature translates OpenTelemetry API calls into the agent's own transaction and segment model, so it's still subject to the same memory behavior described above. Using the standalone OpenTelemetry SDK with its own OTLP exporter avoids the agent's transaction/segment tracking entirely.

For more information, see Introduction to OpenTelemetry and New Relic.

Copyright © 2026 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.