Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
finagle: Add missing imports in docs
Problem

Finagle docs are outdated and not consistent.
Solution

1. Add imports to _all_ the examples in docs
2. Be consistent in temrs of styles for code literals (monospace)
3. Add a couple of new Finagle's companion projects

RB_ID=780793
  • Loading branch information
vkostyukov authored and jenkins committed Jan 11, 2016
1 parent 9334bdd commit 12a8f1c
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 242 deletions.
47 changes: 23 additions & 24 deletions doc/src/sphinx/Clients.rst
Expand Up @@ -545,6 +545,8 @@ again on success or when the back-off schedule runs out.
See the FAQ to :ref:`better understand <faq_failedfastexception>` why clients
might be seeing ``com.twitter.finagle.FailedFastException``'s.

.. _disabling_fail_fast:

The `Fail Fast` module is enabled by default for all of the Finagle clients except for
``Memcached.client`` one. The following example demonstrates how to explicitly disable it for a
particular client.
Expand Down Expand Up @@ -769,30 +771,27 @@ as failures and can do so by using ``ThriftMuxResponseClassifier.ThriftException
.. rubric:: Footnotes

.. [#backoff] Most of the backoff strategies implemented in Finagle are inspired by Mark
Brooker's `blog post <http://www.awsarchitectureblog.com/2015/03/backoff.html>`_.
Brooker's `blog post <http://www.awsarchitectureblog.com/2015/03/backoff.html>`_.
.. [#experimental] This configuration was developed to target specific problems we encounter at Twitter
and should be considered experimental. Note that its API may change as we continue to
understand its place in the stack.
.. [#experimental] This configuration was developed to target specific problems we encounter
at Twitter and should be considered experimental. Note that its API may change as we continue
to understand its place in the stack.
.. [#example] Configuration parameters/values provided in this example are only demonstrate the API usage,
not the real world values. We do not recommend blindly applying those values to production
systems.
.. [#example] Configuration parameters/values provided in this example are only to demonstrate
the API usage, not the real world values. We do not recommend blindly applying those values
to production systems.
.. [#raise] The `Future#within` variant creates a new future
that invokes raise on the future when the timeout occurs.
The affects of which are dependent on the producer of the
future. In most cases, Finagle will attempt to cancel the
request if it hasn't already been dispatched. If it has been
dispatched, the behavior is dependent on the protocol (without
protocol support Finagle needs to tear down the session to signal
cancellation).
.. [#raise] The `Future#within` variant creates a new future that invokes raise on the future
when the timeout occurs. The affects of which are dependent on the producer of the future.
In most cases, Finagle will attempt to cancel the request if it hasn't already been dispatched.
If it has been dispatched, the behavior is dependent on the protocol (without protocol
support Finagle needs to tear down the session to signal cancellation).
.. [#p2c] Michael Mitzenmacher. 2001. The Power of Two Choices in
Randomized Load Balancing. IEEE Trans. Parallel Distrib. Syst. 12, 10 (October 2001), 1094-1104.
.. [#p2c] Michael Mitzenmacher. 2001. The Power of Two Choices in Randomized Load Balancing.
IEEE Trans. Parallel Distrib. Syst. 12, 10 (October 2001), 1094-1104.
.. [#p2c_bounds] The maximum load on any server is roughly bound by `ln(ln(n))` where n is the number
of requests.
.. [#p2c_bounds] The maximum load on any server is roughly bound by `ln(ln(n))` where n is
the number of requests.
.. [#p2c_jmh] Our micro benchmark exposes the stark differences:
Expand All @@ -801,11 +800,11 @@ as failures and can do so by using ``ThriftMuxResponseClassifier.ThriftException
HeapBalancer.getAndPut 1000 avgt 10 8686.479 ± 261.360 ns/op
P2CBalancer.leastLoadedGetAndPut 1000 avgt 10 1692.388 ± 103.164 ns/op

.. [#weights_api] Weights are built into all the balancers except for the ``HeapBalancer``. The API exposed
for this is in ``com.twitter.finagle.WeightedSocketAddress``. The name resolver that
translates logical destinations to ``com.twitter.finagle.Addr`` can wrap concrete
address with a `Double` which influences the balancer's distributor during the
selection process.
.. [#weights_api] Weights are built into all the balancers except for the ``HeapBalancer``.
The API exposed for this is in ``com.twitter.finagle.WeightedSocketAddress``. The name
resolver that translates logical destinations to ``com.twitter.finagle.Addr`` can wrap
concrete address with a `Double` which influences the balancer's distributor during the
selection process.
.. [#probation] See ``com.twitter.finagle.loadbalancer.LoadBalancerFactory#EnableProbation``
Expand Down
42 changes: 21 additions & 21 deletions doc/src/sphinx/Extending.rst
Expand Up @@ -43,17 +43,17 @@ components included in Finagle's clients are discussed in the

While we can imagine stacking such modules together in a manual
fashion—for example, by building it bottoms-up, passing each
`ServiceFactory` into the constructor of the next—this technique quickly
``ServiceFactory`` into the constructor of the next—this technique quickly
becomes onerous; it become very difficult to:

- parameterize each component, for example to set the sizes of
connection pools.
connection pools
- inject dependencies such as
:api:`StatsReceiver <com.twitter.finagle.stats.StatsReceiver>` implementations;
:util:`StatsReceiver <com.twitter.finagle.stats.StatsReceiver>` implementations
- rearrange any part of the stack, for example to remove an
unused timeout filter;
unused timeout filter
- modify the stack for a specific use, for example to replace
the connection pooling implementation or the load balancer.
the connection pooling implementation or the load balancer

Traditionally, the :api:`ClientBuilder
<com.twitter.finagle.builder.ClientBuilder>` and :api:`ServerBuilder
Expand All @@ -75,11 +75,11 @@ The stack abstraction also formalizes the concept of a *parameter*—i.e.
a map of values used to construct an object. :api:`Stack.Params <com.twitter.finagle.Stack$.Params>`
is a kind of type-safe map used to hold parameters.

`Stack` and `Param` work together like this: `Stack` represents the stack
``Stack`` and ``Param`` work together like this: ``Stack`` represents the stack
of modules. These modules aren't *materialized*. Rather, they represent
a constructor for a `ServiceFactory` that accepts a `Params` map. Thus,
to extract the final `ServiceFactory` that represents the entirety of the stack,
we simply call `stack.make(params)`.
a constructor for a ``ServiceFactory`` that accepts a ``Params`` map. Thus,
to extract the final ``ServiceFactory`` that represents the entirety of the stack,
we simply call ``stack.make(params)``.

Finagle defines default (polymorphic) stacks for both
:api:`clients <com.twitter.finagle.client.StackClient$.newStack>` and
Expand Down Expand Up @@ -130,13 +130,13 @@ We define a listener in our server implementation:
:language: scala

This implements the :src:`Listener <com/twitter/finagle/server/Listener.scala>`
interface that exposes a `listen` method:
interface that exposes a ``listen`` method:

.. code-block:: scala
def listen(addr: SocketAddress)(serveTransport: Transport[In, Out] => Unit)
That is, given a socket address to bind and listen, `serveTransport` is dispatched
That is, given a socket address to bind and listen, ``serveTransport`` is dispatched
for each new connection established.

For example, here is a simple echo server:
Expand All @@ -156,7 +156,7 @@ We can now send requests over this socket and have them echoed back:
> echo "hello" | nc localhost 8080
> hello

The `serveTransport` function defined above is primitive. For example,
The ``serveTransport`` function defined above is primitive. For example,
it closes each connection after one read and write. Finagle provides tools
to provision a transport with more sophisticated behavior.

Expand All @@ -171,7 +171,7 @@ is written back to the transport. Additionally, the
server dispatcher drains existing requests before
closing a transport.

We could translate our `serveTransport` function to use this facility:
We could translate our ``serveTransport`` function to use this facility:

.. includecode:: code/client-server-anatomy/Echo.scala#simplelisten
:language: scala
Expand All @@ -186,18 +186,18 @@ StdStackServer

Finagle's :src:`StdStackServer
<com/twitter/finagle/server/StackServer.scala>` provides appropriate
features for building a robust server. It puts together a `Listener`
and a `Dispatcher` in much the same way we just did. `StdStackServer`
also layers a `Stack` on top of it (e.g. to provide timeouts, stats,
features for building a robust server. It puts together a ``Listener``
and a ``Dispatcher`` in much the same way we just did. ``StdStackServer``
also layers a ``Stack`` on top of it (e.g. to provide timeouts, stats,
concurrency control, tracing, etc.) and takes care of graceful
shutdown, so that outstanding requests are drained before a server
exits. The resulting server is fully parameterized, providing a simple
and standard way to receive parameters and dependencies.

Using the listener and dispatcher as above, we define our full server.
The abstract type parameters `In` and `Out` are used when the type of
`Listener` differs from the type of `Server`. This is common when some protocol
processing is done in the `Dispatcher`.
The abstract type parameters ``In`` and ``Out`` are used when the type of
``Listener`` differs from the type of ``Server``. This is common when some protocol
processing is done in the ``Dispatcher``.

.. includecode:: code/client-server-anatomy/Echo.scala#server
:language: scala
Expand Down Expand Up @@ -270,7 +270,7 @@ Assuming we have a server willing to listen, we can expect a response:
A Robust Client
---------------

Our client is a Service, so we can supply additional
Our client is a ``Service``, so we can supply additional
behavior to make our client more robust using
filters:

Expand Down Expand Up @@ -306,7 +306,7 @@ features including
and :ref:`connection pooling <watermark_pool>` per host. See the section
on :ref:`client modules <client_modules>` for more details.

Putting together a `StdStackClient` is simple:
Putting together a ``StdStackClient`` is simple:

.. includecode:: code/client-server-anatomy/Echo.scala#client
:language: scala
Expand Down
106 changes: 64 additions & 42 deletions doc/src/sphinx/FAQ.rst
Expand Up @@ -27,17 +27,28 @@ A simplified code snippet that exemplifies the intra-process structure:

.. code-block:: scala
val client = Mysql.newService(...)
val service: Service[Req, Rep] = new Service[Req, Rep] {
def apply(req: Req): Future[Rep] = {
client(...)
import com.twitter.finagle.Mysql
import com.twitter.finagle.mysql
import com.twitter.finagle.Service
import com.twitter.finagle.Http
import com.twitter.finagle.http
import com.twitter.util.Future
val client: Service[mysql.Request, mysql.Result] =
Mysql.client.newService(...)
val service: Service[http.Request, http.Response] =
new Service[http.Request, http.Response] {
def apply(req: http.Request): Future[http.Response] = {
client(...).map(req: mysql.Result => http.Response())
}
}
}
val server = Http.serve(..., service)
val server = Http.server.serve(..., service)
.. [#] "Chained" in this context means that calling `Future#raise`
will reach the interrupt handler on the Future that represents
the rpc call to the client. This is clearly the case in the above
the RPC call to the client. This is clearly the case in the above
example where the call to the client is indeed the returned Future.
However, this will still hold if the client call was in the context
of a Future combinator (ex. `Future#select`, `Future#join`, etc.)
Expand All @@ -51,21 +62,25 @@ You can disable this behavior by using the :API:`MaskCancelFilter <com.twitter.f

.. code-block:: scala
val service: Service[Req, Rep] = ...
val masked = new MaskCancelFilter[Req, Rep]
import com.twitter.finagle.filter.MaskCancelFilter
import com.twitter.finagle.Http
import com.twitter.finagle.http.
val service: Service[http.Request, http.Response] =
Http.client.newService("http://twitter.com")
val masked = new MaskCancelFilter[http.Request, http.Response]
val maskedService = masked andThen service
val maskedService = masked.andThen(service)
Note that most protocols do not natively support request cancellations
(though modern RPC protocols like :doc:`Mux <Protocols>`
do). In practice, this means that for these protocols, we need to disconnect
the client to signal cancellation, which in turn can cause undue connection
churn.
.. note:: Most protocols do not natively support request cancellations (though modern RPC
protocols like :doc:`Mux <Protocols>` do). In practice, this means that for these
protocols, we need to disconnect the client to signal cancellation, which in turn
can cause undue connection churn.

Why is com.twitter.common.zookeeper#server-set not found?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some of our libraries still aren't published to maven central. If you add
Some of our libraries still aren't published to maven central. If you add

.. code-block:: scala
Expand All @@ -79,25 +94,30 @@ published externally, but not yet to maven central.
How do I configure clients and servers with Finagle 6 APIs?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

As of :doc:`6.x <changelog>`, We introduced a new, preferred API for constructing Finagle ``Client``\s and ``Server``\s.
Where the old API used ``ServerBuilder``\/``ClientBuilder`` with Codecs, the new APIs use
``Proto.newClient`` [#]_.
As of :doc:`6.x <changelog>`, We introduced a new, preferred API for constructing Finagle
``Client``\s and ``Server``\s. Where the old API used ``ServerBuilder``\/``ClientBuilder``
with ``Codec``s, the new APIs use ``Protocol.client.newClient`` and ``Protocol.server.serve`` [#]_.

Old APIs:
Old ``ClientBuilder`` APIs::

.. code-block:: scala
val client = ClientBuilder()
.codec(Http)
.hosts("localhost:10000,localhost:10001,localhost:10003")
.hostConnectionLimit(1)
.build()
import com.twitter.finagle.builder.ClientBuilder
import com.twitter.finagle.http.Http
New APIs:
val client = ClientBuilder()
.codec(Http)
.hosts("localhost:10000,localhost:10001,localhost:10003")
.hostConnectionLimit(1)
.build()
New ``Stack`` APIs:

.. code-block:: scala
val client = Http.newService("localhost:10000,localhost:10001")
import com.twitter.finagle.Http
val client = Http.client.newService("localhost:10000,localhost:10001")
The new APIs make timeouts more explicit, but we think we have a pretty good reason
for changing the API this way.
Expand All @@ -111,28 +131,33 @@ For liveness detection, it is actually fine for timeouts to be long. We have a
default of 1 second.

For application requirements, you can use a service normally and then use
`Future#raiseWithin`.
``Future#raiseWithin``.

.. code-block:: scala
val get: Future[HttpResponse] = Http.fetchUrl("http://twitter.com/")
get.raiseWithin(1.ms)
import com.twitter.conversions.time._
import com.twitter.util.Future
import com.twitter.finagle.Http
import com.twitter.finagle.http
val get: Future[http.Response] = Http.fetchUrl("http://twitter.com/")
get.raiseWithin(1.ms)
We found that having all of the extremely granular timeouts was making it harder
for people to use Finagle, since it was hard to reason about what all of the
timeouts did without knowledge of Finagle internals. How is `tcpConnectTimeout`
different from `connectTimeout`? How is a `requestTimeout` different from a
`timeout`? What is an `idleReaderTimeout`? How is it different from
`idleWriterTimeout`? People would often cargo-cult bad configuration settings,
timeouts did without knowledge of Finagle internals. How is ``tcpConnectTimeout``
different from ``connectTimeout``? How is a ``requestTimeout`` different from a
``timeout``? What is an ``idleReaderTimeout``? How is it different from
``idleWriterTimeout``? People would often cargo-cult bad configuration settings,
and it would be difficult to recover from the bad situation. We also found that
they were rarely being used correctly, and usually only by very sophisticated
users.

We're encouraging users to avoid encoding application requirements in Finagle,
which was previously too easy to do via methods like `ClientBuilder#retries`, or
`ClientBuilder#timeout`. These are fundamentally application-level concerns–
which was previously too easy to do via methods like ``ClientBuilder#retries``, or
``ClientBuilder#timeout``. These are fundamentally application-level concerns–
you're trying to meet an SLA, etc. In general, in order to do what Finagle is
for, which is to deliver an rpc message to a cluster, we don't think you should
for, which is to deliver an RPC message to a cluster, we don't think you should
need a lot of configuration at all. You should need to specify your protocol,
and a few details about the transport (ssl? no ssl?), but that's about it.

Expand Down Expand Up @@ -161,14 +186,11 @@ marked down as fail fast, then the load balancer will pass requests through, res
``com.twitter.finagle.FailedFastException``.

A related issue is when the load balancer's pool is a single endpoint that is itself a
load balancer (for example an nginx server or a hardware load balancer).
load balancer (for example an Nginx server or a hardware load balancer).
It is important to disable fail fast as the remote load balancer has
the visibility into which endpoints are up.
Disabling fail fast can be done with ``ClientBuilder``:

.. code-block:: scala

clientBuilder.failFast(false)
See :ref:`this example <disabling_fail_fast>`_ on how to disable `Fail Fast` for a given client.

Refer to the :ref:`fail fast <client_fail_fast>` section for further context.

Expand Down

0 comments on commit 12a8f1c

Please sign in to comment.