Skip to content

Commit

Permalink
Merge pull request #19086 from kanderson250/kanderson250-scala-futures
Browse files Browse the repository at this point in the history
chore: update scala-installation-java.mdx to include Futures section
  • Loading branch information
paperclypse authored Oct 28, 2024
2 parents f0ce01b + 17caa51 commit 002ceee
Showing 1 changed file with 44 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
title: Scala instrumentation
title: "Scala instrumentation"
tags:
- Agents
- Java agent
- Custom instrumentation
metaDescription: Supplemental directions for instrumenting the New Relic Java agent with Scala applications.
metaDescription: "Supplemental directions for instrumenting the New Relic Java agent with Scala applications."
redirects:
- /docs/agents/java-agent/frameworks/scala-installation-java
- /docs/java/scala-general-help
Expand Down Expand Up @@ -223,6 +223,48 @@ implicit val ec: ExecutionContext = ???
x.foreach(println) // prints 3 on completion of Future
```

### Futures

New Relic handles Scala futures when they're submitted to the executor, which might lead to a different outcome than you expect. The examples in this section clarifies how this works, so you know what to expect.

This example is calling a transaction block, which takes a future as its parameter and chains it to a second future:

```scala
def chainFutures(f: Future[Unit]) = txn {
f.flatMap( _ => Future{ Thread.sleep(2000) })
}

val f = Future { Thread.sleep(5000) } // future is submitted here
chainFutures(f)
```

From this example, you might expect `chainFutures` to produce a transaction lasting 7 seconds. Instead, the New Relic UI shows the transaction finishing immediately.

The future `f` in the example is submitted by the `Future.apply()` method when it's constructed, before the transaction exists. Because `f` is submitted outside the transaction, any threadhops made during its execution aren't linked together. The downstream future, `Future{ Thread.sleep(2000) }`, is also untracked, because it's submitted in a callback after the transaction context is already gone.

There are a few things you can do to get your transaction to capture the timing of both futures.

* Although you might not be able to change when `f` is submitted, you can time it using the `asyncTrace` method. This times `f` from the moment the transaction is started (but will not track threadhops made by `f`).
* You can use a token to link the callback to the transaction in order to preserve the transaction context during threadhops.
* You can add another `asyncTrace` to time the second future.

With this example, the New Relic UI shows a transaction lasting about 7 seconds, with two segments named “first future” and “second future”:


```scala
def chainFutures(f: Future[Unit]) = txn {
val t = NewRelic.getAgent.getTransaction.getToken
asyncTrace("future one" )(f) //asyncTrace times the first future
.flatMap(_ => {
t.linkAndExpire() //token links across potential threadhops
asyncTrace("future two"){ Future { Thread.sleep(2000) } } //asyncTrace times the second future
})
}
val f = Future { Thread.sleep(5000) }
chainFutures(f)
```


## Instrument Scala with the Java agent API [#using-the-java-api]

Instrument Scala to use the New Relic API class or [annotations](/docs/agents/java-agent/java-agent-api/java-agent-api-instrument-using-annotation).
Expand Down

0 comments on commit 002ceee

Please sign in to comment.