Skip to content
txnap

Fast queries.
Slow transaction?

Your database did its job. What happened in between?

Txnap finds time spent away from the database while an Active Record transaction is open and locks may still be held.

A Ruby gem. No separate service to run.

One transaction, under the lens Illustrative trace
Database eventElapsed time
  1. BEGIN0 ms
  2. UPDATE users112 ms
  3. 742ms

    No database work.

    A row lock may still be held.

  4. INSERT audit_logs854 ms
  5. COMMIT1,024 ms
Total transaction
1,024 ms
Database time
31 ms

The query isn’t always
the slow part.

An external request. A file read. A little too much Ruby. Work between queries can keep a transaction open long after the database is done. Slow-query tools don’t expose that gap. Txnap does.

Watch the real transaction

Measurement starts when the actual BEGIN finishes and ends when COMMIT or ROLLBACK starts. Work before a lazy transaction opens is excluded.

Find the longest gap

See the interval between database events, the SQL on either side, and the application call sites. The default reporting threshold is 100 ms.

Bring the context with it

Get likely lock candidates in your logs, raise in tests, or send the idle_gap.txnap notification to your existing APM.

Less guessing.
A place to look.

The report points to the queries around the gap and the code that issued them. Start there, then move slow non-database work outside the transaction.

Lock detection is heuristic: a candidate isn’t proof that a lock is still held. Txnap observes transactions; it never changes their behavior.

See what is measured
Example log output
Txnap::IdleGapDetected

Transaction held for 1,024 ms (BEGIN → COMMIT)
Database time: 31 ms
Longest non-database gap: 742 ms

Gap occurred between:
  after:  UPDATE "users" SET ...
          (app/services/checkout.rb:88)
  before: INSERT INTO "audit_logs" ...
          (app/services/checkout.rb:131)

Locks possibly held during the gap:
  UPDATE users (row lock)
  app/services/checkout.rb:88

Catch your first nap.

Add the gem, set a threshold, and let your application run. Rails installs the notification subscribers automatically.

Explore all configuration options
  1. 1Add to your Gemfile

    Until the first release, install directly from GitHub.

    gem "txnap", github: "ydah/txnap"
  2. 2Install the gem

    bundle install
  3. 3Configure your initializer

    # config/initializers/txnap.rb
    Txnap.configure do |config|
      config.mode = :log
      config.gap_threshold = 0.1 # seconds
    end

    Using Active Record without Rails? Call Txnap.install! after configuration.