newrelic / newrelic-ruby-agent

New Relic RPM Ruby Agent
https://docs.newrelic.com/docs/apm/agents/ruby-agent/getting-started/introduction-new-relic-ruby/
Apache License 2.0
1.19k stars 599 forks source link

Explore the handling of multiple concurrent transactions #2302

Open fallwith opened 9 months ago

fallwith commented 9 months ago

The agent was originally architected with technology such as Ruby 1.x and Rails 2.x in mind. As Ruby shops grew their web apps in the years that followed with forking webservers or microservices, they essentially continued to really only have each instance of Ruby handle one thing at a time and the use of one New Relic Ruby agent per instance of Ruby worked great. But features such as the fiber scheduler interface, ractors, concurrent-ruby, and Async are driving Ruby concurrency forward in exciting new ways that challenge the agent's 1 active-transaction-on-the-go-at-any-one-time model.

By instrumenting Thread in v8.x and Fiber in v9.x, the agent has made great strides in reporting on what is taking place in a multi-threaded and/or multi-fibered environment. But it reports this information via the traditional single-transaction-at-a-time model. Depending on how their Ruby application is architected, this sometimes leaves a customer with a difficult choice. If they keep Thread/Fiber instrumentation enabled (the default) they will see everything their application does, but multiple distinct operations (such as both a web server request AND a background job request) might sometimes appear reported within a single transaction. Or they can disable Thread/Fiber instrumentation to have better logical operation separation and run the risk of being blind to what their application actually has going on behind the scenes in other threads/fibers while the current transaction is active.

It'd be great if we could keep the Thread/Fiber instrumentation enabled and force more logical operational separation by using multiple concurrent transactions where it makes sense to.

Perhaps we could leverage callstack context...

  1. No transactions in progress
  2. A new transaction is created, record the class and method from the top of the Ruby call stack
  3. While the transaction is open, new activity that could either create a new transaction or segment for an existing transaction is spawned
  4. Check the new activity's callstack against the existing transactions' known context. Only nest if there's a match.
  5. If there's not a match, spawn another transaction concurrently.
workato-integration[bot] commented 9 months ago

https://new-relic.atlassian.net/browse/NR-174924