A Typeclass for abstracting over callbacks and futures
A Typeclass for building Async instances, used internally by ClientFactory.
So we need to take a type-parameterized request object, package it into a monomorphic case class to send to the worker, and have the handler that receives that object able to pattern match out the parameterized object, all without using reflection.
So we need to take a type-parameterized request object, package it into a monomorphic case class to send to the worker, and have the handler that receives that object able to pattern match out the parameterized object, all without using reflection. We can do that with some nifty path-dependant types
A Callback is a Monad for doing in-thread non-blocking operations.
A Callback is a Monad for doing in-thread non-blocking operations. It is essentially a "function builder" that uses function composition to chain together a callback function that is eventually passed to another function.
Normally if you have a function that requires a callback, the function looks something like:
def doSomething(param, param, callBack: result => Unit)
and then you'd call it like
doSomething(arg1, arg2, result => println("got the result"))
This is the well-known continuation pattern, and it something we'd like to avoid due to the common occurrance of deeply nested "callback hell". Instead, the Callback
allows us to define out function as
def doSomething(param1, param2): Callback[Result]
and call it like
val c = doSomething(arg1, arg2) c.map{ result => println("got the result") }.execute()
Thus, in practice working with Callbacks is very similar to working with Futures. The big differences from a future are:
1. Callbacks are not thread safe at all. They are entirely intended to stay inside a single worker. Otherwise just use Futures.
2. The execute() method needs to be called once the callback has been fully built, which unlike futures requires some part of the code to know when a callback is ready to be invoked
When building services, particularly when working with service clients, you
will usually be getting Callbacks back from clients when requests are sent.
*Do not call execute
yourself!* on these Callbacks. They must be returned
as part of request processing, and Colossus will invoke the callback itself.
If you are using Callbacks in some custom situation outside of services, be
aware that exceptions thrown inside a map
or flatMap
are properly caught
and can be recovered using recover
and recoverWith
, however exceptions
thrown in the "final" handler passed to execute
are not caught. This is
because the final block cannot be mapped on (since it is only passed when
the callback is executed) and throwing the exception is preferrable to
suppressing it.
Any exception that is thrown in this block is however rethrown as a
CallbackExecutionException
. Therefore, any "trigger" function you wrap
inside a callback should properly catch this exception.
This exception is only thrown when there's a uncaught exception in the execution block of a Callback.
This exception is only thrown when there's a uncaught exception in the execution block of a Callback. For example,
val c: Callback[Foo] = getCallback() c.execute{ case Success(foo) => throw new Exception("exception") }
will result in a CallbackExecutionException
being thrown, however
c.map{_ => throw new Exception("exception")}.execute()
will not because the exception can still be recovered
A CallbackExecutor
is an actor that mixes in the [CallbackExecution] trait
to complete the execution of a [Callback] that has been converted from a
Future
.
A CallbackExecutor
is an actor that mixes in the [CallbackExecution] trait
to complete the execution of a [Callback] that has been converted from a
Future
. In almost every case, the executor should be an actor running in
a Pinned Dispatcher and shound be the same actor that created the original
Callback, for example, a Colossus worker.
This type is generally only needed when converting a Future to a Callback, or scheduling a Callback for delayed execution.
A CallbackPromise creates a callback which can be eventually filled in with a value.
A CallbackPromise creates a callback which can be eventually filled in with a value. This works similarly to a scala Promise. CallbackPromises are not thread-safe. For thread-safety, simply use a scala Promise and use Callback.fromFuture on it's corresponding Future.
Configuration used to specify a Client's parameters
Configuration used to specify a Client's parameters
The address with which to connect
The request timeout value
The MetricAddress associated with this client
Size of the pending buffer
Size of the sent buffer
When a failure is detected, immediately fail all pending requests.
Retry policy for connections.
How long the connection can remain idle (both sending and receiving data) before it is closed. This should be significantly higher than requestTimeout.
max allowed response size -- larger responses are dropped
Mixed into protocols to provide simple methods for creating clients.
This has to be implemented per codec in order to lift generic Sender traits to a type-specific trait
This has to be implemented per codec in order to lift generic Sender traits to a type-specific trait
For example this is how we go from ServiceClient[HttpRequest, HttpResponse] to HttpClient[Callback]
Thrown when the pending buffer is full
This correctly routes messages to the right worker and handler
A Codec is a stateful object for converting requests/responses to/from DataBuffers.
A Codec is a stateful object for converting requests/responses to/from DataBuffers. IMPORTANT - when decoding, a codec must be able to handle both partial responses and multiple responses in a single DataBuffer. This is why a codec is stateful and returns a Seq[O]
Provide a Codec as well as some convenience functions for usage within in a Service.
Provide a Codec as well as some convenience functions for usage within in a Service.
the type of codec this provider will supply
Thrown when a request is lost in transit
Thrown when there's some kind of data error
This little actor is needed because apparently actors that are running in a pinned dispatcher AND are sending messages to themselves (like workers) cannot use the scheduler...the messages never get sent.
This little actor is needed because apparently actors that are running in a pinned dispatcher AND are sending messages to themselves (like workers) cannot use the scheduler...the messages never get sent. So we get around this by sending a message to this actor living in the default dispatcher which then does the proper scheduling
The LoadBalancingClient will evenly distribute requests across a set of clients.
The LoadBalancingClient will evenly distribute requests across a set of clients. If one client begins failing, the balancer will retry up to numRetries times across the other clients (with each failover hitting different clients to avoid a cascading pileup
Note that the balancer will never try the same client twice for a request, so setting maxTries to a very large number will mean that every client will be tried once
TODO: does this need to actually be a WorkerItem anymore?
Throw when a request is attempted while not connected
The PermutationGenerator creates permutations such that consecutive calls are guaranteed to cycle though all items as the first element.
The PermutationGenerator creates permutations such that consecutive calls are guaranteed to cycle though all items as the first element.
This currently doesn't iterate through every possible permutation, but it does evenly distribute 1st and 2nd tries...needs some more work
Returned when a request has been pending for too long
A Sender is anything that is able to asynchronously send a request and receive a corresponding response
A ServiceClient is a non-blocking, synchronous interface that handles sending atomic commands on a connection and parsing their replies
A ServiceClient is a non-blocking, synchronous interface that handles sending atomic commands on a connection and parsing their replies
Notice - The client will not begin to connect until it is bound to a worker,
so when using the default constructor a service client will not connect on
it's own. You must either call bind
on the client or use the constructor
that accepts a worker
TODO: make underlying output controller data size configurable
A ClientPool is a simple container of open connections.
A ClientPool is a simple container of open connections. It can receive updates and will open/close connections accordingly.
note that config will be copied for each client, replacing only the address
Configuration class for a Service Server Connection Handler
Configuration class for a Service Server Connection Handler
how long to wait until we timeout the request
how many concurrent requests a single connection can be processing
if true, any uncaught exceptions or service-level errors will be logged
toggle request metrics
max size allowed for requests TODO: remove name from config, this should be the same as a server's name and pulled from the ServerRef, though this requires giving the ServiceServer access to the ServerRef
The ServiceServer provides an interface and basic functionality to create a server that processes requests and returns responses over a codec.
The ServiceServer provides an interface and basic functionality to create a server that processes requests and returns responses over a codec.
A Codec is simply the format in which the data is represented. Http, Redis protocol, Memcached protocl are all examples(and natively supported). It is entirely possible to use an additional Codec by creating a Codec to parse the desired protocol.
Requests can be processed synchronously or asynchronously. The server will ensure that all responses are written back in the order that they are received.
This is thrown when a Client is manually disconnected, and subsequent attempt is made to reconnect.
This is thrown when a Client is manually disconnected, and subsequent attempt is made to reconnect. To simplify the internal workings of Clients, instead of trying to reset its internal state, it throws. Create a new Client to reestablish a connection.
UnmappedCallback is essentially an optimization that avoids needing to create a MappedCallback with an identity function
A Typeclass for building Async instances, used internally by ClientFactory. This is needed to get the environment into the Async.