Contexts¶
Finagle uses Contexts, which give you something akin to Java’s ThreadLocals
across asynchronous code.
They give you access to request-scoped state, such as a request’s deadline,
throughout the logical life of a request without requiring them to be explicitly passed.
Finagle explicitly manages them for you across threads and execution
contexts such as Future composition, FuturePools, Timers,
and in some cases — across the client/server boundary.
Contexts can be either local or broadcast. Local contexts do not cross process boundaries while broadcast contexts may be marshalled and transmitted across process boundaries.
Most Context usage is hidden behind other APIs, which means you may not
realize you are using this functionality. This example shows how a ClientId
is available within Timer functions:
scala> import com.twitter.conversions.DurationOps._, com.twitter.finagle.thrift.ClientId, com.twitter.finagle.util.HashedWheelTimer, com.twitter.util.{Await, Future}
import com.twitter.conversions.DurationOps._
import com.twitter.finagle.thrift.ClientId
import com.twitter.finagle.util.HashedWheelTimer
import com.twitter.util.{Await, Future}
scala> val aClientId = ClientId("test-client") // Create a ClientId to use
aClientId: com.twitter.finagle.thrift.ClientId = ClientId(test-client)
scala> val clientIdInTimer: Future[String] =
// Put that ClientId into scope and schedule
// work on a Timer
aClientId.asCurrent {
HashedWheelTimer.Default.doLater(100.milliseconds) {
// Check the value when the Timer's function is
// evaluated 100 milliseconds later
ClientId.current match {
case Some(cId) => cId.name
case None => "no-client-id"
}
}
}
clientIdInTimer: com.twitter.util.Future[String] = Promise@2147108131(state=Interruptible(List(),<function1>))
scala> println(s"Timer saw: '${Await.result(clientIdInTimer)}'")
Timer saw: 'test-client'
Commonly used instances¶
Because Contexts are not passed directly into methods, discovery of which
ones exist is challenging.
To aid with this, here is a listing of some commonly used instances that Finagle
makes available:
Current trace id¶
com.twitter.finagle.tracing.Trace.id —
A broadcast Context that represents this request’s distributed tracing TraceId.
Current client id¶
com.twitter.finagle.thrift.ClientId.current —
A broadcast Context that represents the client identifier of a request.
Current request deadline¶
com.twitter.finagle.context.Deadline.current —
A broadcast Context that represents when the request should be completed by.
Current requeue attempt¶
com.twitter.finagle.context.Requeues.current —
A broadcast Context that represents which requeue attempt this request is.
Requeues are retries on write exceptions (i.e. the original request was never sent to the server).
Will have attempt set to 0 if the request is not a requeue.
Current TLS session¶
com.twitter.finagle.transport.Transport.sslSessionInfo _
A local Context that represents the Transports
com.twitter.finagle.ssl.session.SslSessionInfo. If a TLS session is established,
the SslSessionInfo provides access to the javax.net.ssl.SSLSession, along with
the sessionId, cipherSuite, and both local and peer certificates. This
is an encompassing replacement for com.twitter.finagle.transport.Transport.peerCertificate.
com.twitter.finagle.transport.Transport.peerCertificate —
A local Context that represents the Transports
java.security.cert.Certificate if a TLS session is established.
Upstream Address¶
com.twitter.finagle.context.RemoteInfo.Upstream.addr —
A local Context that represents the upstream (ingress)
java.net.SocketAddress of the current request.
Backup request indicator¶
com.twitter.finagle.context.BackupRequest.wasInitiated —
A broadcast Context that indicates if the request was initiated by a backup
request.
Creating new Contexts¶
Instances should be immutable or must provide proper memory visibility so that changes will be seen across thread boundaries.
Care should be taken when creating new broadcast Contexts as they
will be sent across the entire downstream request graph. Considerations
should include serialization/deserialization costs, serialized size, and
schema evolution.