Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 1578 lines (1144 sloc) 66.265 kB
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1 <a name="Top"></a>
2
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
3 # Finagle Developer Guide (December 15, 2011 Draft)
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
4
5 * <a href="#Quick Start">Quick Start</a>
6 - <a href="#Simple HTTP Server">Simple HTTP Server</a>
7 - <a href="#Simple HTTP Client">Simple HTTP Client</a>
8 - <a href="#Simple Client and Server for Thrift">Simple Client and Server for Thrift</a>
9 * <a href="#Finagle Overview">Finagle Overview</a>
10 - <a href="#Client Features">Client Features</a>
11 - <a href="#Server Features">Server Features</a>
12 - <a href="#Supported Protocols">Supported Protocols</a>
13 * <a href="#Architecture">Architecture</a>
14 - <a href="#Future Objects">Future Objects</a>
15 - <a href="#Service Objects">Service Objects</a>
16 - <a href="#Filter Objects">Filter Objects</a>
17 - <a href="#Codec Objects">Codec Objects</a>
18 - <a href="#Servers">Servers</a>
19 - <a href="#Clients">Clients</a>
20 - <a href="#Threading Model">Threading Model</a>
21 - <a href="#Starting and Stopping Services">Starting and Stopping Servers</a>
22 - <a href="#Exception Handling">Exception Handling</a>
23 * <a href="#Finagle Projects and Packages">Finagle Projects and Packages</a>
24 * <a href="#Using Future Objects">Using Future Objects</a>
25 - <a href="#Future Callbacks">Future Callbacks</a>
26 - <a href="#Future Timeouts">Future Timeouts</a>
27 - <a href="#Future Exceptions">Future Exceptions</a>
28 - <a href="#Promises">Promises</a>
29 - <a href="#Using Future map and flatMap Operations">Using Future map and flatMap Operations</a>
30 - <a href="#Using Future in Scatter/Gather Patterns">Using Future in Scatter/Gather Patterns</a>
31 - <a href="#Using Future Pools">Using Future Pools</a>
32 * <a href="#Creating a Service">Creating a Service</a>
33 * <a href="#Creating Simple Filters">Creating Filters</a>
34 * <a href="#Building a Robust Server">Building a Robust Server</a>
35 * <a href="#Building a Robust Client">Building a Robust Client</a>
36 * <a href="#Creating Filters to Transform Requests and Responses">Creating Filters to Transform Requests and Responses</a>
37 * <a href="#Using ServerSet Objects">Using ServerSet Objects</a>
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
38 * <a href="#Java Design Patterns for Finagle">Java Design Patterns for Finagle</a>
39 - <a href="#Using Future Objects With Java">Using Future Objects With Java</a>
40 - <a href="#Imperative Java Style">Imperative Java Style</a>
41 - <a href="#Functional Java Style">Functional Java Style</a>
42 - <a href="#Building a Server in Java">Building a Server in Java</a>
43 - <a href="#Building a Client in Java">Building a Client in Java</a>
44 - <a href="#Implementing a Pool for Blocking Operations in Java">Implementing a Pool for Blocking Operations in Java</a>
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
45 * <a href="#Additional Samples">Additional Samples</a>
46 * <a href="#API Reference Documentation">API Reference Documentation</a>
47
48 <a name="Quick Start"></a>
49
50 ## Quick Start
51
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
52 Finagle is an asynchronous network stack for the JVM that you can use to build *asynchronous* Remote Procedure Call (RPC) clients and servers in Java, Scala, or any JVM-hosted language. Finagle provides a rich set of tools that are protocol independent.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
53
54 The following Quick Start sections show how to implement simple RPC servers and clients in Scala and Java. The first example shows the creation a simple HTTP server and corresponding client. The second example shows the creation of a Thrift server and client. You can use these examples to get started quickly and have something that works in just a few lines of code. For a more detailed description of Finagle and its features, start with <a href="#Finagle Overview">Finagle Overview</a> and come back to Quick Start later.
55
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
56 **Note:** The examples in this section include both Scala and Java implementations. Other sections show only Scala examples. For more information about Java, see <a href="#Java Design Patterns for Finagle">Java Design Patterns for Finagle</a>.
57
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
58 [Top](#Top)
59
60 <a name="Simple HTTP Server"></a>
61
62 ### Simple HTTP Server
63
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
64 Consider a very simple implementation of an HTTP server and client in which clients make HTTP GET requests and the server responds to each one with an HTTP 200 OK response.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
65
66 The following server, which is shown in both Scala and Java, responds to a client's HTTP request with an HTTP 200 OK response:
67
68 ##### Scala HTTP Server Implementation
69
70 val service: Service[HttpRequest, HttpResponse] = new Service[HttpRequest, HttpResponse] { // 1
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
71 def apply(request: HttpRequest) = Future(new DefaultHttpResponse(HTTP_1_1, OK)) // 2
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
72 }
73
74 val address: SocketAddress = new InetSocketAddress(10000) // 3
75
76 val server: Server[HttpRequest, HttpResponse] = ServerBuilder() // 4
77 .codec(Http)
78 .bindTo(address)
b12649c @mariusae [split] finagle README: fix up examples so that they actually compile
mariusae authored
79 .name("HttpServer")
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
80 .build(service)
81
82 ##### Java HTTP Server Implementation
83
84 Service<HttpRequest, HttpResponse> service = new Service<HttpRequest, HttpResponse>() { // 1
85 public Future<HttpResponse> apply(HttpRequest request) {
86 return Future.value( // 2
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
87 new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
88 }
89 };
90
91 ServerBuilder.safeBuild(service, ServerBuilder.get() // 4
92 .codec(Http.get())
b12649c @mariusae [split] finagle README: fix up examples so that they actually compile
mariusae authored
93 .name("HttpServer")
94 .bindTo(new InetSocketAddress("localhost", 10000))); // 3
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
95
96
97 ##### HTTP Server Code Annotations
98
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
99 1. Create a new Service that handles HTTP requests and responses.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
100 2. For each request, respond asynchronously with an HTTP 200 OK response. A Future instance represents an asynchronous operation that may be performed later.
101 3. Specify the socket addresses on which your server responds; in this case, on port 10000 of localhost.
102 4. Build a server that responds to HTTP requests on the socket and associate it with your service. In this case, the Server builder specifies
103 - an HTTP codec, which ensures that only valid HTTP requests are received by the server
104 - the host socket that listens for requests
105 - the association between the server and the service, which is specified by `.build` in Scala and the first argument to `safeBuild` in Java
106 - the name of the service
107
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
108 **Note:** For more information about the Java implementation, see <a href="#Java Design Patterns for Finagle">Java Design Patterns for Finagle</a>.
109
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
110 [Top](#Top)
111
112 <a name="Simple HTTP Client"></a>
113
114 ### Simple HTTP Client
115
116 The client, which is shown in both Scala and Java, connects to the server, and issues a simple HTTP GET request:
117
118 ##### Scala HTTP Client Implementation
119
120 val client: Service[HttpRequest, HttpResponse] = ClientBuilder() // 1
121 .codec(Http)
122 .hosts(address)
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
123 .hostConnectionLimit(1)
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
124 .build()
125
126 // Issue a request, get a response:
127 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/") // 2
128 val responseFuture: Future[HttpResponse] = client(request) // 3
129 onSuccess { response => println("Received response: " + response) // 4
130 }
131
132 ##### Java HTTP Client Implementation
133
134 Service<HttpRequest, HttpResponse> client = ClientBuilder.safeBuild(ClientBuilder.get() // 1
135 .codec(Http.get())
136 .hosts("localhost:10000")
137 .hostConnectionLimit(1));
138
139 // Issue a request, get a response:
140 HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"); // 2
141 client.apply(request).addEventListener(new FutureEventListener<HttpResponse>() { // 3
142 public void onSuccess(HttpResponse response) { // 4
143 System.out.println("received response: " + response);
144 }
145 public void onFailure(Throwable cause) {
146 System.out.println("failed with cause: " + cause);
147 }
148 });
149
150 ##### HTTP Client Code Annotations
151
152 1. Build a client that sends an HTTP request to the host identified by its socket address. In this case, the Client builder specifies
153 - an HTTP request filter, which ensures that only valid HTTP requests are sent to the server
154 - a list of the server's hosts that can process requests
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
155 - maximum number of connections from the client to the host
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
156 - to build this client service
157 2. Create an HTTP GET request.
158 3. Make the request to the host identified in your client.
159 4. Specify a callback, `onSuccess`, that Finagle executes when the response arrives.
160
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
161 **Note:** Although the example shows building the client and execution of the built client on the same thread, you should build your clients only once and execute them separately. There is no requirement to maintain a 1:1 relationship between building a client and executing a client.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
162
163 [Top](#Top)
164
165 <a name="Simple Client and Server for Thrift"></a>
166
167 ### Simple Client and Server for Thrift
168
169 Apache Thrift is a binary communication protocol that defines available methods using an interface definition language (IDL). Consider the following Thrift IDL definition for a `Hello` service that defines only one method, `hi`:
170
171 service Hello {
172 string hi();
173 }
174
175 #### Simple Thrift Server
176
177 In this Finagle example, the `ThriftServer` object implements the `Hello` service defined using the Thrift IDL.
178
179 ##### Scala Thrift Server Implementation
180
181 object ThriftServer {
182 def main(args: Array[String]) {
183 // Implement the Thrift Interface
184 val processor = new Hello.ServiceIface { // 1
185 def hi() = Future.value("hi") // 2
186 }
187
188 val service = new Hello.Service(processor, new TBinaryProtocol.Factory()) // 3
189
190 val server: Server = ServerBuilder() // 4
191 .name("HelloService")
192 .bindTo(new InetSocketAddress(8080))
193 .codec(ThriftServerFramedCodec())
194 .build(service)
195 }
196 }
197
198 ##### Java Thrift Server Implementation
199
200 Hello.ServiceIface processor = new Hello.ServiceIface() { // 1
201 public Future<String> hi() { // 2
202 return Future.value("hi");
203 }
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
204 }
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
205
206 ServerBuilder.safeBuild( // 4
207 new Hello.Service(processor, new TBinaryProtocol.Factory()), // 3
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
208 ServerBuilder.get()
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
209 .name("HelloService")
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
210 .codec(ThriftServerFramedCodec.get())
211 // .codec(ThriftServerFramedCodecFactory$.MODULE$) previously
b12649c @mariusae [split] finagle README: fix up examples so that they actually compile
mariusae authored
212 .bindTo(new InetSocketAddress(8080)));
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
213
214 ##### Thrift Server Code Annotations
215
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
216 1. Create a Thrift processor that implements the Thrift service interface, which is `Hello` in this example.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
217 2. Implement the service interface. In this case, the only method in the interface is `hi`, which only returns the string `"hi"`. The returned value must be a `Future` to conform the signature of a Finagle `Service`. (In a more robust example, the Thrift service might perform asynchronous communication.)
218 3. Create an adapter from the Thrift processor to a Finagle service. In this case, the `Hello` Thrift service uses `TBinaryProtocol` as the Thrift protocol.
219 4. Build a server that responds to Thrift requests on the socket and associate it with your service. In this case, the Server builder specifies
220 - the name of the service
221 - the host addresses that can receive requests
222 - the Finagle-provided `ThriftServerFramedCodec` codec, which ensures that only valid Thrift requests are received by the server
223 - the association between the server and the service
224
225 #### Simple Thrift Client
226
227 In this Finagle example, the `ThriftClient` object creates a Finagle client that executes the methods defined in the `Hello` Thrift service.
228
229 ##### Scala Thrift Client Implementation
230
231 object ThriftClient {
232 def main(args: Array[String]) {
233 // Create a raw Thrift client service. This implements the
234 // ThriftClientRequest => Future[Array[Byte]] interface.
235 val service: Service[ThriftClientRequest, Array[Byte]] = ClientBuilder() // 1
236 .hosts(new InetSocketAddress(8080))
237 .codec(ThriftClientFramedCodec())
238 .hostConnectionLimit(1)
239 .build()
240
241 // Wrap the raw Thrift service in a Client decorator. The client provides
242 // a convenient procedural interface for accessing the Thrift server.
243 val client = new Hello.ServiceToClient(service, new TBinaryProtocol.Factory()) // 2
244
245 client.hi() onSuccess { response => // 3
246 println("Received response: " + response)
247 } ensure {
248 service.release() // 4
249 }
250 }
251 }
252
253 ##### Java Thrift Client Implementation
254
255 Service<ThriftClientRequest, byte[]> client = ClientBuilder.safeBuild(ClientBuilder.get() // 1
256 .hosts(new InetSocketAddress(8080))
257 .codec(new ThriftClientFramedCodecFactory())
258 .hostConnectionLimit(1));
259
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
260 Hello.ServiceIface client =
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
261 new Hello.ServiceToClient(client, new TBinaryProtocol.Factory()); // 2
262
263 client.hi().addEventListener(new FutureEventListener<String>() {
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
264 public void onSuccess(String s) { // 3
265 System.out.println(s);
266 }
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
267
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
268 public void onFailure(Throwable t) {
269 System.out.println("Exception! ", t.toString());
270 }
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
271 });
272
273 ##### Thrift Client Code Annotation
bf776ce @mariusae minimal README.
mariusae authored
274
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
275 1. Build a client that sends a Thrift protocol-based request to the host identified by its socket address. In this case, the Client builder specifies
276 - the host addresses that can receive requests
277 - the Finagle-provided `ThriftServerFramedCodec` codec, which ensures that only valid Thrift requests are received by the server
278 - to build this client service
279 2. Make a remote procedure call to the `Hello` Thrift service's `Hi` method. This returns a `Future` that represents the eventual arrival of a response.
280 3. When the response arrives, the `onSuccess` callback executes to print the result.
281 4. Release resources acquired by the client.
bf776ce @mariusae minimal README.
mariusae authored
282
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
283 [Top](#Top)
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
284
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
285 <a name="Finagle Overview"></a>
286
287 ## Finagle Overview
288
289 Use the Finagle library to implement asynchronous Remote Procedure Call (RPC) clients and servers. Finagle is flexible enough to support a variety of RPC styles, including request-response, streaming, and pipelining; for example, HTTP pipelining and Redis pipelining. It also makes it easy to work with stateful RPC styles; for example, RPCs that require authentication and those that support transactions.
290
291 [Top](#Top)
292
293 <a name="Client Features"></a>
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
294
235b186 improving readme
Nick Kallen authored
295 ### Client Features
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
296
235b186 improving readme
Nick Kallen authored
297 * Connection Pooling
298 * Load Balancing
299 * Failure Detection
300 * Failover/Retry
391f93d corrected readme
Nick Kallen authored
301 * Distributed Tracing (a la [Dapper](http://research.google.com/pubs/pub36356.html))
235b186 improving readme
Nick Kallen authored
302 * Service Discovery (e.g., via Zookeeper)
303 * Rich Statistics
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
304 * Native OpenSSL Bindings
305
306 [Top](#Top)
307
308 <a name="Server Features"></a>
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
309
235b186 improving readme
Nick Kallen authored
310 ### Server Features
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
311
235b186 improving readme
Nick Kallen authored
312 * Backpressure (to defend against abusive clients)
313 * Service Registration (e.g., via Zookeeper)
391f93d corrected readme
Nick Kallen authored
314 * Distributed Tracing
235b186 improving readme
Nick Kallen authored
315 * Native OpenSSL bindings
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
316
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
317 [Top](#Top)
318
319 <a name="Supported Protocols"></a>
320
235b186 improving readme
Nick Kallen authored
321 ### Supported Protocols
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
322
235b186 improving readme
Nick Kallen authored
323 * HTTP
391f93d corrected readme
Nick Kallen authored
324 * HTTP streaming (Comet)
235b186 improving readme
Nick Kallen authored
325 * Thrift
326 * Memcached/Kestrel
327 * More to come!
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
328
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
329 [Top](#Top)
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
330
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
331 <a name="Architecture"></a>
391f93d corrected readme
Nick Kallen authored
332
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
333 ## Architecture
391f93d corrected readme
Nick Kallen authored
334
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
335 Finagle extends the stream-oriented [Netty](http://www.jboss.org/netty) model to provide asynchronous requests and responses for remote procedure calls (RPC). Internally, Finagle manages a service stack to track outstanding requests, responses, and the events related to them. Finagle uses a Netty pipeline to manage connections between the streams underlying request and response messages. The following diagram shows the relationship between your RPC client or server, Finagle, Netty, and Java libraries:
391f93d corrected readme
Nick Kallen authored
336
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
337 ![Relationship between your RPC client or server, Finagle, Netty, and Java Libraries (doc/FinagleRelationship.png)](https://github.com/twitter/finagle/raw/master/doc/FinagleRelationship.png)
391f93d corrected readme
Nick Kallen authored
338
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
339 Finagle manages a [Netty pipeline](http://docs.jboss.org/netty/3.2/api/org/jboss/netty/channel/ChannelPipeline.html) for servers built on Finagle RPC services. Netty itself is built on the Java [NIO](http://download.oracle.com/javase/1.5.0/docs/api/java/nio/channels/package-summary.html#package_description) library, which supports asynchronous IO. While an understanding of Netty or NIO might be useful, you can use Finagle without this background information.
391f93d corrected readme
Nick Kallen authored
340
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
341 Finagle objects are the building blocks of RPC clients and servers:
391f93d corrected readme
Nick Kallen authored
342
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
343 - <a href="#Future Objects">Future objects</a> enable asynchronous operations required by a service
344 - <a href="#Service Objects">Service objects</a> perform the work associated with a remote procedure call
345 - <a href="#Filter Objects">Filter objects</a> enable you to transform data or act on messages before or after the data or messages are processed by a service
346 - <a href="#Codec Objects">Codec objects</a> decode messages in a specific protocol before they are handled by a service and encode messages before they are transported to a client or server.
391f93d corrected readme
Nick Kallen authored
347
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
348 You combine these objects to create:
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
349
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
350 - <a href="#Servers">Servers</a>
351 - <a href="#Clients">Clients</a>
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
352
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
353 Finagle provides a `ServerBuilder` and a `ClientBuilder` object, which enable you to configure <a href="#Servers">servers</a> and <a href="#Clients">clients</a>, respectively.
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
354
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
355 [Top](#Top)
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
356
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
357 <a name="Future Objects"></a>
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
358
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
359 ### Future Objects
068ec55 reformatting
Nick Kallen authored
360
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
361 In Finagle, `Future` objects are the unifying abstraction for all asynchronous computation. A `Future` represents a computation that has not yet completed, which can either succeed or fail. The two most basic ways to use a `Future` are to
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
362
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
363 * block and wait for the computation to return
364 * register a callback to be invoked when the computation eventually succeeds or fails
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
365
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
366 For more information about `Future` objects, see <a href="#Using Future Objects">Using Future Objects</a>.
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
367
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
368 <!-- Future has methods, such as `times`, `parallel`, and `whileDo` that implement advanced control-flow patterns. -->
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
369
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
370 [Top](#Top)
235b186 improving readme
Nick Kallen authored
371
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
372 <a name="Service Objects"></a>
235b186 improving readme
Nick Kallen authored
373
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
374 ### Service Objects
235b186 improving readme
Nick Kallen authored
375
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
376 A `Service` is simply a function that receives a request and returns a `Future` object as a response. You extend the abstract `Service` class to implement your service; specifically, you must define an `apply` method that transforms the request into the future response.
235b186 improving readme
Nick Kallen authored
377
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
378 [Top](#Top)
235b186 improving readme
Nick Kallen authored
379
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
380 <a name="Filter Objects"></a>
235b186 improving readme
Nick Kallen authored
381
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
382 ### Filter Objects
235b186 improving readme
Nick Kallen authored
383
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
384 It is useful to isolate distinct phases of your application into a pipeline. For example, you may need to handle exceptions, authorization, and other phases before your service responds to a request. A `Filter` provides an easy way to decouple the protocol handling code from the implementation of the business rules. A `Filter` wraps a `Service` and, potentially, converts the input and output types of the service to other types. For an example of a filter, see <a href="#Creating Filters to Transform Requests and Responses">Creating Filters to Transform Requests and Responses</a>.
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
385
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
386 A `SimpleFilter` is a kind of `Filter` that does not convert the request and response types. For an example of a simple filter, see <a href="#Creating Filters">Creating Filters</a>.
235b186 improving readme
Nick Kallen authored
387
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
388 [Top](#Top)
235b186 improving readme
Nick Kallen authored
389
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
390 <a name="Codec Objects"></a>
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
391
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
392 ### Codec Objects
068ec55 reformatting
Nick Kallen authored
393
78d152c @mariusae [split] finagle/README: update, fixes
mariusae authored
394 A `Codec` object encodes and decodes _wire_ protocols, such as HTTP. You can use Finagle-provided `Codec` objects for encoding and decoding the Thrift, HTTP, memcache, Kestrel, HTTP chunked streaming (ala Twitter Streaming) prptocols. You can also extend the `CodecFactory` class to implement encoding and decoding of other protocols.
235b186 improving readme
Nick Kallen authored
395
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
396 [Top](#Top)
235b186 improving readme
Nick Kallen authored
397
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
398 <a name="Servers"></a>
235b186 improving readme
Nick Kallen authored
399
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
400 ### Servers
235b186 improving readme
Nick Kallen authored
401
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
402 In Finagle, RPC servers are built out of a `Service` and zero or more `Filter` objects. You apply filters to the service request after which you execute the service itself:
235b186 improving readme
Nick Kallen authored
403
5248a58 @mariusae [split] finagle·doc: fix up image links
mariusae authored
404 ![Relationship between a service and filters (doc/Filters.png)](https://github.com/twitter/finagle/raw/master/doc/Filters.png)
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
405
406 Typically, you use a `ServerBuilder` to create your server. A `ServerBuilder` enables you to specify the following general attributes:
407
408 <table>
409 <thead>
410 <tr>
411 <th>Attribute</th>
412 <th>Description</th>
413 <th>Default Value</th>
414 </tr>
415 </thead>
416 <tr>
417 <td>codec</td>
418 <td>Object to handle encoding and decoding of the service's request/response protocol</td>
419 <td><I>None</I></td>
420 </tr>
421 <tr>
422 <td>statsReceiver</td>
423 <td>Statistics receiver object, which enables logging of important events and statistics</td>
424 <td><I>None</I></td>
425 </tr>
426 <tr>
427 <td>name</td>
428 <td>Name of the service</td>
429 <td><I>None</I></td>
430 </tr>
431 <tr>
432 <td>bindTo</td>
433 <td>The IP host:port pairs on which to listen for requests; <CODE>localhost</CODE> is assumed if the host is not specified</td>
434 <td><I>None</I></td>
435 </tr>
436 <tr>
437 <td>logger</td>
438 <td>Logger object</td>
439 <td><I>None</I></td>
440 </tr>
441 </tbody>
442 </table>
443
444 You can specify the following attributes to handle fault tolerance and manage clients:
445
446 <table>
447 <thead>
448 <tr>
449 <th>Attribute</th>
450 <th>Description</th>
451 <th>Default Value</th>
452 </tr>
453 </thead>
454 <tr>
455 <td>maxConcurrentRequests</td>
456 <td>Maximum number of requests that can be handled concurrently by the server</td>
457 <td><I>None</I></td>
458 </tr>
459 <tr>
460 <td>hostConnectionMaxIdleTime</td>
461 <td>Maximum time that this server can be idle before the connection is closed</td>
462 <td><I>None</I></td>
463 </tr>
464 <tr>
465 <td>hostConnectionMaxLifeTime</td>
466 <td>Maximum time that this server can be connected before the connection is closed</td>
467 <td><I>None</I></td>
468 </tr>
469 <tr>
470 <td>requestTimeout</td>
471 <td>Maximum time to complete a request</td>
472 <td><I>None</I></td>
473 </tr>
474 <tr>
475 <td>readTimeout</td>
476 <td>Maximum time to wait for the first byte to be read</td>
477 <td><I>None</I></td>
478 </tr>
479 <tr>
480 <td>writeCompletionTimeout</td>
481 <td>Maximum time to wait for notification of write completion from a client</td>
482 <td><I>None</I></td>
483 </tr>
484 </tbody>
485 </table>
486
487 You can specify the following attributes to manage TCP connections:
488
489 <table>
490 <thead>
491 <tr>
492 <th>Attribute</th>
493 <th>Description</th>
494 <th>Default Value</th>
495 </tr>
496 </thead>
497 <tr>
498 <td>sendBufferSize</td>
499 <td>Requested TCP buffer size for responses</td>
500 <td><I>None</I></td>
501 </tr>
502 <tr>
503 <td>recvBufferSize</td>
504 <td>Actual TCP buffer size for requests</td>
505 <td><I>None</I></td>
506 </tr>
507 </tbody>
508 </table>
509
510 You can also specify these attributes:
511
512 <table>
513 <thead>
514 <tr>
515 <th>Attribute</th>
516 <th>Description</th>
517 <th>Default Value</th>
518 </tr>
519 </thead>
520 <tr>
521 <td>tls</td>
522 <td>The kind of transport layer security</td>
523 <td><I>None</I></td>
524 </tr>
525 <tr>
526 <td>channelFactory</td>
527 <td>Channel service factory object</td>
528 <td><I>None</I></td>
529 </tr>
530 <tr>
531 <td>traceReceiver</td>
532 <td>Trace receiver object</td>
533 <td>new <CODE>NullTraceReceiver</CODE> object</td>
534 </tr>
535 </tbody>
536 </table>
537
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
538 Once you have defined your `Service`, it can be bound to an IP socket address, thus becoming an RPC server.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
539
540 [Top](#Top)
541
542 <a name="Clients"></a>
543
544 ### Clients
545
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
546 Finagle makes it easy to build RPC clients with connection pooling, load balancing, logging, and statistics reporting. The balancing strategy is to pick the endpoint with the least number of outstanding requests, which is similar to _least connections_ in other load balancers. The load-balancer deliberately introduces jitter to avoid synchronicity (and thundering herds) in a distributed system.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
547
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
548 Your code should separate building the client from invocation of the client. A client, once built, can be used with _lazy binding_, saving the resources required to build a client. Note: The examples, which show the creation of the client and its first execution together, represent the first-execution scenario. Typically, subsequent execution of the client does not require rebuilding.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
549
550 Finagle will retry the request in the event of an error, up to the number of times specified; however, Finagle **does not assume your RPC service is Idempotent**. Retries occur only when the request is known to be idempotent, such as in the event of TCP-related `WriteException` errors, for which the RPC has not been transmitted to the remote server.
551
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
552 A robust way to use RPC clients is to have an upper-bound on how long to wait for a response to arrive. With `Future` objects, you can
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
553
554 * block, waiting for a response to arrive and throw an exception if it does not arrive in time.
555 * register a callback to handle the result if it arrives in time, and register another callback to invoke if the result does not arrive in time
556
557 A client is a `Service` and can be wrapped by `Filter` objects. Typically, you call `ClientBuilder` to create your client service. `ClientBuilder` enables you to specify the following general attributes:
558
559 <table>
560 <thead>
561 <tr>
562 <th>Attribute</th>
563 <th>Description</th>
564 <th>Default Value</th>
565 </tr>
566 </thead>
567 <tr>
568 <td>name</td>
569 <td>Name of the service</td>
570 <td><I>None</I></td>
571 </tr>
572 <tr>
573 <td>codec</td>
574 <td>Object to handle encoding and decoding of the service's request/response protocol</td>
575 <td><I>None</I></td>
576 </tr>
577 <tr>
578 <td>statsReceiver</td>
579 <td>Statistics receiver object, which enables logging of important events and statistics</td>
580 <td><I>None</I></td>
581 </tr>
582 <tr>
583 <td>loadStatistics</td>
584 <td>How often to load statistics from the server</td>
585 <td><B>(60, 10.seconds)</B></td>
586 </tr>
587 <tr>
588 <td>logger</td>
589 <td>A <CODE>Logger</CODE> object with which to log Finagle messages</td>
590 <td><I>None</I></td>
591 </tr>
592 <tr>
593 <td>retries</td>
594 <td>Number of retries per request (only applies to recoverable errors)</td>
595 <td><I>None</I></td>
596 </tr>
597 </tbody>
598 </table>
599
600 You can specify the following attributes to manage the host connection:
601
602 <table>
603 <thead>
604 <tr>
605 <th>Attribute</th>
606 <th>Description</th>
607 <th>Default Value</th>
608 </tr>
609 </thead>
610 <tr>
611 <td>connectionTimeout</td>
612 <td>Time allowed to establish a connection</td>
613 <td><B>10.milliseconds</B></td>
614 </tr>
615 <tr>
616 <td>requestTimeout</td>
617 <td>Request timeout</td>
618 <td><I>None</I>, meaning it waits forever</td>
619 </tr>
620 <tr>
621 <td>hostConnectionLimit</td>
622 <td>Number of connections allowed from this client to the host</td>
623 <td><I>None</I></td>
624 </tr>
625 <tr>
626 <td>hostConnectionCoresize</td>
627 <td>Host connection's cache allocation</td>
628 <td><I>None</I></td>
629 </tr>
630 <tr>
631 <td>hostConnectionIdleTime</td>
78d152c @mariusae [split] finagle/README: update, fixes
mariusae authored
632 <td></td>
633 <td><I>None</I></td>
634 </tr>
635 </tr>
636 <tr>
637 <td>hostConnectionMaxWaiters</td>
638 <td>The maximum number of queued requests awaiting a connection</td>
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
639 <td><I>None</I></td>
640 </tr>
641 <tr>
642 <td>hostConnectionMaxIdleTime</td>
643 <td>Maximum time that the client can be idle until the connection is closed</td>
644 <td><I>None</I></td>
645 </tr>
646 <tr>
647 <td>hostConnectionMaxLifeTime</td>
648 <td>Maximum time that client can be connected before the connection is closed</td>
649 <td><I>None</I></td>
650 </tr>
651 </tbody>
652 </table>
653
654 You can specify the following attributes to manage TCP connections:
655
656 <table>
657 <thead>
658 <tr>
659 <th>Attribute</th>
660 <th>Description</th>
661 <th>Default Value</th>
662 </tr>
663 </thead>
664 <tr>
665 <td>sendBufferSize</td>
666 <td>Requested TCP buffer size for responses</td>
667 <td><I>None</I></td>
668 </tr>
669 <tr>
670 <td>recvBufferSize</td>
671 <td>Actual TCP buffer size for requests</td>
672 <td><I>None</I></td>
673 </tr>
674 </tbody>
675 </table>
676
677 You can also specify these attributes:
678
679 <table>
680 <tr>
681 <th>Attribute</th>
682 <th>Description</th>
683 <th>Default Value</th>
684 </tr>
685 <tr>
686 <td>cluster</td>
687 <td>The cluster connections associated with the client</td>
688 <td><I>None</I></td>
689 </tr>
690 <tr>
691 <td>channelFactory</td>
692 <td>Channel factory associated with this client</td>
693 <td><I>None</I></td>
694 </tr>
695 <tr>
696 <td>tls</td>
697 <td>The kind of transport layer security</td>
698 <td><I>None</I></td>
699 </tr>
700 </table>
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
701
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
702 If you are using _stateful protocols_, such as those used for transaction processing or authentication, you should call `buildFactory`, which creates a `ServiceFactory` to support stateful connections.
703
704 [Top](#Top)
705
706 <a name="Threading Model"></a>
235b186 improving readme
Nick Kallen authored
707
189948e @mariusae [split] finagle: don't conflate asynchronicity with an event loop in …
mariusae authored
708 ### Threading Model
235b186 improving readme
Nick Kallen authored
709
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
710 The Finagle threading model requires that you avoid blocking operations in the Finagle event loop. Finagle-provided methods do not block; however, you could inadvertently implement a client, service or a `Future` callback that blocks.
235b186 improving readme
Nick Kallen authored
711
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
712 Blocking events include but are not limited to
235b186 improving readme
Nick Kallen authored
713
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
714 * network calls
715 * system calls
716 * database calls
235b186 improving readme
Nick Kallen authored
717
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
718 Note: You do not need to be concerned with long-running or CPU intensive operations if they do not block. Examples of these operations include image processing operations, public key cryptography, or anything that might take a non-trivial amount of clock time to perform. Only operations that block in Finagle are of concern. Because Finagle and its event loop use a relatively low number of threads, blocked threads can cause performance issues.
235b186 improving readme
Nick Kallen authored
719
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
720 Consider the following diagram, which shows how a client uses the Finagle event loop:
235b186 improving readme
Nick Kallen authored
721
5248a58 @mariusae [split] finagle·doc: fix up image links
mariusae authored
722 ![Relationship between your threads and Finagle (doc/ThreadEx.png)](https://github.com/twitter/finagle/raw/master/doc/ThreadEx.png)
cbaee89 @mariusae [split] document event loop.
mariusae authored
723
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
724 Your threads, which are shown on the left, are allowed to block. When you call a Finagle method or Finagle calls a method for you, it dispatches execution of these methods to its internal threads. Thus, the Finagle event loop and its threads cannot block without degrading the performance of other clients and servers that use the same Finagle instance.
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
725
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
726 In complex RPC operations, it may be necessary to perform blocking operations. In these cases, you must set up your own thread pool and use `Future` or `FuturePool` objects to execute the blocking operation on your own thread. Consider the following diagram:
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
727
5248a58 @mariusae [split] finagle·doc: fix up image links
mariusae authored
728 ![Handling operations that block (doc/ThreadExNonBlockingServer.png)](https://github.com/twitter/finagle/raw/master/doc/ThreadExNonBlockingServer.png)
235b186 improving readme
Nick Kallen authored
729
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
730 In this example, you can use a `FuturePool` object to provide threads for blocking operations outside of Finagle. Finagle can then dispatch the blocking operation to your thread. For more information about `FuturePool` objects, see <a href="#Using Future Pools">Using Future Pools</a>.
235b186 improving readme
Nick Kallen authored
731
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
732 [Top](#Top)
235b186 improving readme
Nick Kallen authored
733
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
734 <a name="Starting and Stopping Servers"></a>
235b186 improving readme
Nick Kallen authored
735
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
736 ### Starting and Stopping Servers
235b186 improving readme
Nick Kallen authored
737
78d152c @mariusae [split] finagle/README: update, fixes
mariusae authored
738 A server automatically starts when you call `build` on the server after assigning the IP address on which it runs. To stop a server, call its `close` method. The server will immediately stop accepting requests; however, the server will continue to process outstanding requests until all have been handled or until a specific duration has elapsed. You specify the duration when you call `close`. In this way, the server is allowed to drain out outstanding requests but will not run indefinitely. You are responsible for releasing all resources when the server is no longer needed.
235b186 improving readme
Nick Kallen authored
739
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
740 [Top](#Top)
235b186 improving readme
Nick Kallen authored
741
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
742 <a name="Finagle Projects and Packages"></a>
235b186 improving readme
Nick Kallen authored
743
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
744 ## Finagle Projects and Packages
235b186 improving readme
Nick Kallen authored
745
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
746 The `Core` project contains the execution framework, Finagle classes, and supporting classes, whose objects are only of use within Finagle. The `Core` project includes the following packages:
235b186 improving readme
Nick Kallen authored
747
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
748 * `builder` - contains `ClientBuilder`, `ServerBuilder`
749 * `channel`
750 * `http`
751 * `loadbalancer`
752 * `pool`
753 * `service`
754 * `stats`
755 * `tracing`
756 * `util`
235b186 improving readme
Nick Kallen authored
757
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
758 It also contains packages to support remote procedure calls over Kestrel, Thrift, streams, clusters, and provides statistics collection (Ostrich).
235b186 improving readme
Nick Kallen authored
759
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
760 The `Util` project contains classes, such as `Future`, which are both generally useful and specifically useful to Finagle.
235b186 improving readme
Nick Kallen authored
761
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
762 [Top](#Top)
235b186 improving readme
Nick Kallen authored
763
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
764 <a name="Using Future Objects"></a>
235b186 improving readme
Nick Kallen authored
765
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
766 ## Using Future Objects
235b186 improving readme
Nick Kallen authored
767
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
768 In the simplest case, you can use `Future` to block for a request to complete. Consider an example that blocks for an HTTP GET request:
235b186 improving readme
Nick Kallen authored
769
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
770 // Issue a request, get a response:
771 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
772 val responseFuture: Future[HttpResponse] = client(request)
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
773
774 In this example, a client issuing the request will wait forever for a response unless you specified a value for the `requestTimeout` attribute when you built the <a href="#Clients">client</a>.
235b186 improving readme
Nick Kallen authored
775
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
776 Consider another example:
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
777
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
778 val responseFuture: Future[String] = executor.schedule(job)
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
779
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
780 In this example, the value of `responseFuture` is not available until after the scheduled job has finished executing and the caller will block until `responseFuture` has a value.
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
781
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
782 **Note:** For examples of using Finagle `Future` objects in Java, see <a href="#Using Future Objects With Java">Using Future Objects With Java</a>.
783
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
784 [Top](#Top)
d652c54 some tupos
Nick Kallen authored
785
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
786 <a name="Future Callbacks"></a>
d652c54 some tupos
Nick Kallen authored
787
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
788 ### Future Callbacks
6feb234 links to Scaladoc for Future and Channel
Nick Kallen authored
789
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
790 In cases where you want to continue execution immediately, you can specify a callback. The callback is identified by the `onSuccess` keyword:
d652c54 some tupos
Nick Kallen authored
791
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
792 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
793 val responseFuture: Future[HttpResponse] = client(request)
794 responseFuture onSuccess { responseFuture =>
795 println(responseFuture)
235b186 improving readme
Nick Kallen authored
796 }
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
797
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
798 [Top](#Top)
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
799
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
800 <a name="Future Timeouts"></a>
d652c54 some tupos
Nick Kallen authored
801
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
802 ### Future Timeouts
d652c54 some tupos
Nick Kallen authored
803
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
804 In cases where you want to continue execution after some amount of elapsed time, you can specify the length of time to wait in the `Future` object. The following example waits 1 second before displaying the value of the response:
d652c54 some tupos
Nick Kallen authored
805
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
806 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
807 val responseFuture: Future[HttpResponse] = client(request)
808 println(responseFuture(1.second))
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
809
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
810 In the above example, you do not know whether the response timed out before the request was satisfied. To determine what kind of response you actually received, you can provide two callbacks, one to handle `onSuccess` conditions and one for `onFailure` conditions. You use the `within` method of `Future` to specify how long to wait for the response. Finagle also creates a `Timer` thread on which to wait until one of the conditions are satisfied. Consider the following example:
391f93d corrected readme
Nick Kallen authored
811
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
812 import com.twitter.finagle.util.Timer._
813 ...
814 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
815 val responseFuture: Future[HttpResponse] = client(request)
816 responseFuture.within(1.second) onSuccess { response =>
817 println("responseFuture)
818 } onFailure {
819 case e: TimeoutException => ...
391f93d corrected readme
Nick Kallen authored
820 }
821
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
822 If a timeout occurs, Finagle takes the `onFailure` path. You can use a `TimeoutException` object to display a message or take other actions.
d652c54 some tupos
Nick Kallen authored
823
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
824 [Top](#Top)
391f93d corrected readme
Nick Kallen authored
825
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
826 <a name="Future Exceptions"></a>
827
828 ### Future Exceptions
391f93d corrected readme
Nick Kallen authored
829
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
830 To set up an exception, specify the action in a `try` block and handle failures in a `catch` block. Consider an example that handles `Future` timeouts as an exception:
831
832 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
833 val responseFuture: Future[HttpResponse] = client(request)
d652c54 some tupos
Nick Kallen authored
834 try {
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
835 println(responseFuture(1.second))
d652c54 some tupos
Nick Kallen authored
836 } catch {
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
837 case e: TimeoutException => ...
d652c54 some tupos
Nick Kallen authored
838 }
839
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
840 In this example, after 1 second, either the HTTP response is displayed or the `TimeoutException` is thrown.
841
842 [Top](#Top)
843
844 <a name="Promises"></a>
845
846 ### Promises
847
848 `Promise` is a subclass of `Future`. Although a `Future` can only be read, a `Promise` can be both read and written.
849 Usually a producer makes a `Promise` and casts it to a `Future` before giving it to the consumer. The following example shows how this might be useful in the case where you intend to make a `Future` service but need to anticipate errors:
850
851 def make() = {
852 ...
853 val promise = new Promise[Service[Req, Rep]]
854 ... {
855 case Ok(myObject) =>
856 ...
857 promise() = myConfiguredObject
858 case Error(cause) =>
859 promise() = Throw(new ...Exception(cause))
860 case Cancelled =>
861 promise() = Throw(new WriteException(new ...Exception))
862 }
863 promise
d652c54 some tupos
Nick Kallen authored
864 }
78d152c @mariusae [split] finagle/README: update, fixes
mariusae authored
865
866 You are discouraged from creating your own Promises. Instead, where possible, use `Future` combinators to compose actions (discussed next).
d652c54 some tupos
Nick Kallen authored
867
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
868 [Top](#Top)
869
870 <a name="Using Future map and flatMap Operations"></a>
871
872 ### Using Future map and flatMap Operations
873
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
874 In addition to waiting for results to return, `Future` can be transformed in interesting ways. For instance, it is possible to convert a `Future[String]` to a `Future[Int]` by using `map`:
388ddab streams
Nick Kallen authored
875
876 val stringFuture: Future[String] = Future("1")
877 val intFuture: Future[Int] = stringFuture map (_.toInt)
878
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
879 Similar to `map`, you can use `flatMap` to easily _pipeline_ a sequence of `Futures`:
388ddab streams
Nick Kallen authored
880
881 val authenticateUser: Future[User] = User.authenticate(email, password)
882 val lookupTweets: Future[Seq[Tweet]] = authenticateUser flatMap { user =>
883 Tweet.findAllByUser(user)
884 }
885
886 In this example, `Tweet.findAllByUser(user)` is a function of type `User => Future[Seq[Tweet]]`.
d652c54 some tupos
Nick Kallen authored
887
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
888 <!--
388ddab streams
Nick Kallen authored
889
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
890 [Top](#Top)
891
892 <a name="Using Future handle and rescue Operations"></a>
893
894 ### Using Future handle and rescue Operations
388ddab streams
Nick Kallen authored
895
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
896 // TODO
388ddab streams
Nick Kallen authored
897
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
898 -->
899
900 [Top](#Top)
901
902 <a name="Using Future in Scatter/Gather Patterns"></a>
903
904 ### Using Future in Scatter/Gather Patterns
905
906 For scatter/gather patterns, the challenge is to issue a series of requests in parallel and wait for all of them to arrive. To wait for a sequence of `Future` objects to return, you can define a sequence to hold the objects and use the `Future.collect` method to wait for them, as follows:
907
908 val myFutures: Seq[Future[Int]] = ...
391f93d corrected readme
Nick Kallen authored
909 val waitTillAllComplete: Future[Seq[Int]] = Future.collect(myFutures)
388ddab streams
Nick Kallen authored
910
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
911 A more complex variation of scatter/gather pattern is to perform a sequence of asynchronous operations and harvest only those that return within a certain time, ignoring those that don't return within the specified time. For example, you might want to issue a set of parallel requests to _N_ partitions of a search index; those that don't return in time are assumed to be empty. The following example allows 1 second for the query to return:
388ddab streams
Nick Kallen authored
912
913 import com.twitter.finagle.util.Timer._
914
915 val results: Seq[Future[Result]] = partitions.map { partition =>
916 partition.get(query).within(1.second) handle {
917 case _: TimeoutException => EmptyResult
918 }
919 }
391f93d corrected readme
Nick Kallen authored
920 val allResults: Future[Seq[Result]] = Future.collect(timedResults)
388ddab streams
Nick Kallen authored
921
922 allResults onSuccess { results =>
923 println(results)
924 }
d652c54 some tupos
Nick Kallen authored
925
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
926 [Top](#Top)
ec2ae88 @bierbaum updated readme (still needs a lot of work)
bierbaum authored
927
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
928 <a name="Using Future Pools"></a>
388ddab streams
Nick Kallen authored
929
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
930 ### Using Future Pools
6feb234 links to Scaladoc for Future and Channel
Nick Kallen authored
931
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
932 A `FuturePool` object enables you to place a blocking operation on its own thread. In the following example, a service's `apply` method, which executes in the Finagle event loop, creates the `FuturePool` object and places the blocking operation on a thread associated with the `FuturePool` object. The `apply` method returns immediately without blocking.
388ddab streams
Nick Kallen authored
933
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
934 class ThriftFileReader extends Service[String, Array[Byte]] {
935 val diskIoFuturePool = FuturePool(Executors.newFixedThreadPool(4))
936
937 def apply(path: String) = {
938 val blockingOperation = {
939 scala.Source.fromFile(path) // potential to block
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
940 }
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
941 // give this blockingOperation to the future pool to execute
942 diskIoFuturePool(blockingOperation)
943 // returns immediately while the future pool executes the operation on a different thread
944 }
388ddab streams
Nick Kallen authored
945 }
946
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
947 **Note:** For an example implementation of a thread pool in Java, see <a href="#Implementing a Pool for Blocking Operations in Java">Implementing a Pool for Blocking Operations in Java</a>.
388ddab streams
Nick Kallen authored
948
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
949 [Top](#Top)
388ddab streams
Nick Kallen authored
950
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
951 <a name="Creating a Service"></a>
388ddab streams
Nick Kallen authored
952
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
953 ## Creating a Service
388ddab streams
Nick Kallen authored
954
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
955 The following example extends the `Service` class to respond to an HTTP request:
956
957 class Respond extends Service[HttpRequest, HttpResponse] {
958 def apply(request: HttpRequest) = {
959 val response = new DefaultHttpResponse(HTTP_1_1, OK)
960 response.setContent(copiedBuffer(myContent, UTF_8))
961 Future.value(response)
962 }
388ddab streams
Nick Kallen authored
963 }
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
964
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
965 [Top](#Top)
388ddab streams
Nick Kallen authored
966
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
967 <a name="Creating Simple Filters"></a>
388ddab streams
Nick Kallen authored
968
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
969 ## Creating Simple Filters
388ddab streams
Nick Kallen authored
970
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
971 The following example extends the `SimpleFilter` class to throw an exception if the HTTP authorization header contains a different value than the specified string:
972
973 class Authorize extends SimpleFilter[HttpRequest, HttpResponse] {
974 def apply(request: HttpRequest, continue: Service[HttpRequest, HttpResponse]) = {
975 if ("shared secret" == request.getHeader("Authorization")) {
976 continue(request)
977 } else {
978 Future.exception(new IllegalArgumentException("You don't know the secret"))
979 }
980 }
981 }
391f93d corrected readme
Nick Kallen authored
982
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
983 The following example extends the `SimpleFilter`class to set the HTTP response code if an error occurs and return the error and stack trace in the response:
984
985 class HandleExceptions extends SimpleFilter[HttpRequest, HttpResponse] {
986 def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
987 service(request) handle { case error =>
988 val statusCode = error match {
989 case _: IllegalArgumentException =>
990 FORBIDDEN
991 case _ =>
992 INTERNAL_SERVER_ERROR
993 }
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
994
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
995 val errorResponse = new DefaultHttpResponse(HTTP_1_1, statusCode)
996 errorResponse.setContent(copiedBuffer(error.getStackTraceString, UTF_8))
997
998 errorResponse
999 }
391f93d corrected readme
Nick Kallen authored
1000 }
1001 }
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
1002
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
1003 For an example implementation using a `Filter` object, see <a href="#Creating Filters to Transform Requests and Responses">Creating Filters to Transform Requests and Responses</a>.
1004
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1005 [Top](#Top)
391f93d corrected readme
Nick Kallen authored
1006
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1007 <a name="Building a Robust Server"></a>
388ddab streams
Nick Kallen authored
1008
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1009 ## Building a Robust Server
1010
1011 The following example encapsulates the filters and service in the previous examples and defines the execution order of the filters, followed by the service. The `ServerBuilder` object specifies the service that indicates the execution order along with the codec and IP address on which to bind the service:
391f93d corrected readme
Nick Kallen authored
1012
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1013 object HttpServer {
1014 class HandleExceptions extends SimpleFilter[HttpRequest, HttpResponse] {...}
1015 class Authorize extends SimpleFilter[HttpRequest, HttpResponse] {...}
1016 class Respond extends Service[HttpRequest, HttpResponse] {... }
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
1017
388ddab streams
Nick Kallen authored
1018
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1019 def main(args: Array[String]) {
1020 val handleExceptions = new HandleExceptions
1021 val authorize = new Authorize
1022 val respond = new Respond
1023
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
1024 val myService: Service[HttpRequest, HttpResponse]
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1025 = handleExceptions andThen authorize andThen respond
1026
1027 val server: Server = ServerBuilder()
1028 .codec(Http)
1029 .bindTo(new InetSocketAddress(8080))
1030 .build(myService)
1031 }
388ddab streams
Nick Kallen authored
1032 }
1033
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1034 In this example, the `HandleExceptions` filter is executed before the `authorize` filter. All filters are executed before the service. The server is robust not because of its complexity; rather, it is robust because it uses filters to remove issues before the service executes.
1035
1036 [Top](#Top)
391f93d corrected readme
Nick Kallen authored
1037
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1038 <a name="Building a Robust Client"></a>
391f93d corrected readme
Nick Kallen authored
1039
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1040 ## Building a Robust Client
1041
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
1042 A robust client has little to do with the lines of code (SLOC) that goes into it; rather, the robustness depends on how you configure the client and the testing you put into it. Consider the following HTTP client:
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1043
1044 val client = ClientBuilder()
1045 .codec(Http)
1046 .hosts("localhost:10000,localhost:10001,localhost:10003")
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1047 .hostConnectionLimit(1) // max number of connections at a time to a host
1048 .connectionTimeout(1.second) // max time to spend establishing a TCP connection
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1049 .retries(2) // (1) per-request retries
1050 .reportTo(new OstrichStatsReceiver) // export host-level load data to ostrich
1051 .logger(Logger.getLogger("http"))
1052 .build()
1053
1054 The `ClientBuilder` object creates and configures a load balanced HTTP client that balances requests among 3 (local) endpoints. The Finagle balancing strategy is to pick the endpoint with the least number of outstanding requests, which is similar to a *least connections* strategy in other load balancers. The Finagle load balancer deliberately introduces jitter to avoid synchronicity (and thundering herds) in a distributed system. It also supports failover.
1055
1056 The following examples show how to invoke this client from Scala and Java, respectively:
1057
1058 ##### Scala Client Invocation
391f93d corrected readme
Nick Kallen authored
1059
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1060 val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, Get, "/")
1061 val futureResponse: Future[HttpResponse] = client(request)
391f93d corrected readme
Nick Kallen authored
1062
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1063 ##### Java Client Invocation
391f93d corrected readme
Nick Kallen authored
1064
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1065 HttpRequest request = new DefaultHttpRequest(HTTP_1_1, Get, "/")
1066 Future<HttpResponse> futureResponse = client.apply(request)
391f93d corrected readme
Nick Kallen authored
1067
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1068 For information about using `Future` objects with Java, see <a href="#Using Future Objects With Java">Using Future Objects With Java</a>.
391f93d corrected readme
Nick Kallen authored
1069
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1070 [Top](#Top)
388ddab streams
Nick Kallen authored
1071
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1072 <a name="Creating Filters to Transform Requests and Responses"></a>
1073
1074 ## Creating Filters to Transform Requests and Responses
1075
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
1076 The following example extends the `Filter` class to authenticate requests. The request is transformed into an HTTP response before being handled by the `AuthResult` service. In this case, the `RequireAuthentication` filter does not transform the resulting HTTP response:
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1077
1078 class RequireAuthentication(val p: ...)
1079 extends Filter[Request, HttpResponse, AuthenticatedRequest, HttpResponse]
1080 {
1081 def apply(request: Request, service: Service[AuthenticatedRequest, HttpResponse]) = {
1082 p.authenticate(request) flatMap {
1083 case AuthResult(AuthResultCode.OK, Some(passport: OAuthPassport), _, _) =>
1084 service(AuthenticatedRequest(request, passport))
1085 case AuthResult(AuthResultCode.OK, Some(passport: SessionPassport), _, _) =>
1086 service(AuthenticatedRequest(request, passport))
1087 case ar: AuthResult =>
1088 Trace.record("Authentication failed with " + ar)
1089 Future.exception(new RequestUnauthenticated(ar.resultCode))
1090 }
1091 }
388ddab streams
Nick Kallen authored
1092 }
1093
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1094 In this example, the `flatMap` object enables pipelining of the requests.
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1095
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1096 [Top](#Top)
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1097
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1098 <!--
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1099
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1100 <a name="Creating Combinators to Distribute Processing Tasks"></a>
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1101
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1102 ## Creating Combinators to Distribute Processing Tasks
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1103
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1104 // TODO
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1105
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1106 [Top](#Top)
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1107
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1108 -->
1109
1110 <a name="Using ServerSet Objects"></a>
1111
1112 ## Using ServerSet Objects
1113
f3ee11d @evnm [split] Fix deprecated link to ServerSet documentation in README.
evnm authored
1114 `finagle-serversets` is an implementation of the Finagle Cluster interface using `com.twitter.com.zookeeper` [ServerSets](http://twitter.github.com/commons/apidocs/#com.twitter.common.zookeeper.ServerSet).
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1115
1116 You can instantiate a `ServerSet` object as follows:
1117
1118 val serverSet = new ServerSetImpl(zookeeperClient, "/twitter/services/...")
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1119 val cluster = new ZookeeperServerSetCluster(serverSet)
1120
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1121 Servers join a cluster, as in the following example:
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1122
1123 val serviceAddress = new InetSocketAddress(...)
1124 val server = ServerBuilder()
1125 .bindTo(serviceAddress)
1126 .build()
1127
1128 cluster.join(serviceAddress)
1129
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1130 A client can access a cluster, as follows:
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1131
1132 val client = ClientBuilder()
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1133 .cluster(cluster)
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1134 .hostConnectionLimit(1)
d1e2a51 @mariusae opensource finagle-serversets, now that dependencies are
mariusae authored
1135 .codec(new StringCodec)
1136 .build()
1137
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1138 [Top](#Top)
1139
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1140 <a name="Java Design Patterns for Finagle"></a>
1141
1142 ## Java Design Patterns for Finagle
1143
1144 The implementations of RPC servers and clients in Java are similar to Scala implementations. You can write your Java services in the _imperative_ style, which is the traditional Java programming style, or you can write in the _functional_ style, which uses functions as objects and is the basis for Scala. Most differences between Java and Scala implementations are related to exception handling.
1145
1146 [Top](#Top)
1147
1148 <a name="Using Future Objects With Java"></a>
1149
1150 ### Using Future Objects With Java
1151
1152 A `Future` object in Java is defined as `Future<`_Type_`>`, as in the following example:
1153
1154 Future<String> future = executor.schedule(job);
1155
1156 **Note:** The `Future` class is defined in `com.twitter.util.Future` and is not the same as the Java `Future` class.
1157
1158 You can explicitly call the `Future` object's `get` method to retrieve the contents of a `Future` object:
1159
1160 // Wait indefinitely for result
1161 String result = future.get();
1162
1163 Calling `get` is the more common pattern because you can more easily perform exception handling. See <a href="#Handling Synchronous Responses With Exception Handling">Handling Synchronous Responses With Exception Handling</a> for more information.
1164
1165 You can alternatively call the `Future` object's `apply` method. Arguments to the `apply` method are passed as functions:
1166
1167 // Wait up to 1 second for result
1168 String result = future.apply(Duration.apply(1, SECOND));
1169
1170 This technique is most appropriate when exception handling is not an issue.
1171
1172 [Top](#Top)
1173
1174 <a name="Imperative Java Style"></a>
1175
1176 ### Imperative Java Style
1177
1178 The following example shows the _imperative_ style, which uses an event listener that responds to a change in the `Future` object and calls the appropriate method:
1179
1180 Future<String> future = executor.schedule(job);
1181 future.addEventListener(
1182 new FutureEventListener<String>() {
1183 public void onSuccess(String value) {
1184 println(value);
1185 }
1186 public void onFailure(Throwable t) ...
1187 }
1188 )
1189
1190 [Top](#Top)
1191
1192 <a name="Functional Java Style"></a>
1193
1194 ### Functional Java Style
1195
1196
1197 The following example shows the _functional_ style, which is similar to the way in which you write Scala code:
1198
1199 Future<String> future = executor.schedule(job);
1200 future.onSuccess( new Function<String, Void>() {
1201 public Void apply(String value) { System.out.println(value);
1202 } ).onFailure(...).ensure(...);
1203
1204 The following example shows the _functional_ style for the `map` method:
1205
1206 Future<String> future = executor.schedule(job);
1207 Future<Integer> result = future.map(new Function<String, Integer>() {
1208 public Integer apply(String value) { return Integer.valueOf(value);
1209 }
1210
1211 [Top](#Top)
1212
1213 <a name="Building a Server in Java"></a>
1214
1215 ### Building a Server in Java
1216
1217 When you create a server in Java, you have several options. You can create a server that processes requests synchronously or asynchronously. You must also choose an appropriate level of exception handling. In all cases, either a `Future` or an exception is returned.This section shows several techniques that are relevant for servers written in Java:
1218
1219 * <a href="#Server Imports">Server Imports</a>
1220 * <a href="#Performing Synchronous Operations">Performing Synchronous Operations</a>
1221 * <a href="#Performing Asynchronous Operations">Performing Asynchronous Operations</a>
1222 * <a href="#Invoking the Server">Invoking the Server</a>
1223
1224 [Top](#Top)
1225
1226 <a name="Server Imports"></a>
1227
1228 #### Server Imports
1229
1230 As you write a server in Java, you will become familiar with the following packages and classes. Some `netty` classes are specifically related to HTTP. Most of the classes you will use are defined in the `com.twitter.finagle` and `com.twitter.util` packages.
1231
1232 import java.net.InetSocketAddress;
1233
1234 import org.jboss.netty.buffer.ChannelBuffers;
1235 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
1236 import org.jboss.netty.handler.codec.http.HttpRequest;
1237 import org.jboss.netty.handler.codec.http.HttpResponse;
1238 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
1239 import org.jboss.netty.handler.codec.http.HttpVersion;
1240
1241 import com.twitter.finagle.Service;
1242 import com.twitter.finagle.builder.ServerBuilder;
1243 import com.twitter.finagle.http.Http;
1244 import com.twitter.util.Future;
1245 import com.twitter.util.FutureEventListener;
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
1246 import com.twitter.util.FutureTransformer;
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1247
1248 [Top](#Top)
1249
1250 <a name="Performing Synchronous Operations"></a>
1251
1252 #### Performing Synchronous Operations
1253
1254 If your server can respond synchronously, you can use the following pattern to implement your service:
1255
1256 public class HTTPServer extends Service<HttpRequest, HttpResponse> {
1257 public Future<HttpResponse> apply(HttpRequest request) {
1258 // If I can generate the response synchronously, then I just do this.
1259 try {
1260 HttpResponse response = processRequest(request);
1261 return Future.value(response);
1262 } catch (MyException e) {
1263 return Future.exception(e);
1264 }
1265
1266 In this example, the `try` `catch` block causes the server to either return a response or an exception.
1267
1268 [Top](#Top)
1269
1270 <a name="Performing Asynchronous Operations"></a>
1271
1272 #### Performing Asynchronous Operations
1273
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
1274 In Java, you can implement asynchronous operations by calling a `Future` object's `getContentAsync` method to obtain the content from an asynchronous request. The `Future` object's `transformedBy` method transforms the content of the `Future` object from one data type to another, with the help of a `FutureTransformer` object. You typically override the object's `map` method to perform the actual conversion. A `Throwable` object is provided when an exception occurs to communicate information about the kind of exception. The following example shows this pattern:
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1275
1276 public class HTTPServer extends Service<HttpRequest, HttpResponse> {
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
1277 public Future<HttpResponse> apply(HttpRequest request) {
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1278
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
1279 Future<String> contentFuture = getContentAsync(request);
1280 return contentFuture.transformedBy(new FutureTransformer<String, HttpResponse>() {
1281 @Override
1282 public HttpResponse map(String content) {
1283 HttpResponse httpResponse =
1284 new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
1285 httpResponse.setContent(ChannelBuffers.wrappedBuffer(content.getBytes()));
1286 return httpResponse;
1287 }
1288
1289 @Override
1290 public HttpResponse handle(Throwable throwable) {
1291 HttpResponse httpResponse =
1292 new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.SERVICE_UNAVAILABLE);
1293 httpResponse.setContent(ChannelBuffers.wrappedBuffer(throwable.toString().getBytes()));
1294 return httpResponse;
1295 }
f5b9bc2 @mccue Updated scaladoc to add package.scala info and updated README.md
mccue authored
1296 }
1297 });
1298 }
1299
1300 [Top](#Top)
1301
1302 <a name="Invoking the Server"></a>
1303
1304 #### Invoking the Server
1305
1306 The following example shows the instantiation and invocation of the server. Calling the `ServerBuilder`'s `safeBuild` method statically checks arguments to `ServerBuilder`, which prevents a runtime error if a required argument is missing:
1307
1308 public static void main(String[] args) {
1309 ServerBuilder.safeBuild(new HTTPServer(),
1310 ServerBuilder.get()
1311 .codec(Http.get())
1312 .name("HTTPServer")
1313 .bindTo(new InetSocketAddress("localhost", 8080)));
1314
1315 }
1316 }
1317
1318
1319 [Top](#Top)
1320
1321 <a name="Building a Client in Java"></a>
1322
1323 ### Building a Client in Java
1324
1325 When you create a client in Java, you have several options. You can create a client that processes responses synchronously or asynchronously. You must also choose an appropriate level of exception handling. This section shows several techniques that are relevant for clients written in Java:
1326
1327 * <a href="#Client Imports">Client Imports</a>
1328 * <a href="#Creating the Client">Creating the Client</a>
1329 * <a href="#Handling Synchronous Responses">Handling Synchronous Responses</a>
1330 * <a href="#Handling Synchronous Responses With Timeouts">Handling Synchronous Responses With Timeouts</a>
1331 * <a href="#Handling Synchronous Responses With Exception Handling">Handling Synchronous Responses With Exception Handling</a>
1332 * <a href="#Handling Asynchronous Responses">Handling Asynchronous Responses</a>
1333
1334 [Top](#Top)
1335
1336 <a name="Client Imports"></a>
1337
1338 #### Client Imports
1339
1340 As you write a client in Java, you will become familiar with the following packages and classes. Some `netty` classes are specifically related to HTTP. Most of the classes you will use are defined in the `com.twitter.finagle` and `com.twitter.util` packages.
1341
1342 import java.net.InetSocketAddress;
1343 import java.util.concurrent.TimeUnit;
1344
1345 import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
1346 import org.jboss.netty.handler.codec.http.HttpMethod;
1347 import org.jboss.netty.handler.codec.http.HttpRequest;
1348 import org.jboss.netty.handler.codec.http.HttpResponse;
1349 import org.jboss.netty.handler.codec.http.HttpVersion;
1350
1351 import com.twitter.finagle.Service;
1352 import com.twitter.finagle.builder.ClientBuilder;
1353 import com.twitter.finagle.http.Http;
1354 import com.twitter.util.Duration;
1355 import com.twitter.util.FutureEventListener;
1356 import com.twitter.util.Throw;
1357 import com.twitter.util.Try;
1358
1359
1360 [Top](#Top)
1361
1362 <a name="Creating the Client"></a>
1363
1364 #### Creating the Client
1365
1366 The following example shows the instantiation and invocation of a client. Calling the `ClientBuilder`'s `safeBuild` method statically checks arguments to `ClientBuilder`, which prevents a runtime error if a required argument is missing:
1367
1368 public class HTTPClient {
1369 public static void main(String[] args) {
1370 Service<HttpRequest, HttpResponse> httpClient =
1371 ClientBuilder.safeBuild(
1372 ClientBuilder.get()
1373 .codec(Http.get())
1374 .hosts(new InetSocketAddress(8080))
1375 .hostConnectionLimit(1));
1376
1377 **Note:** Choosing a value of 1 for `hostConnectionLimit` eliminates contention for a host.
1378
1379 [Top](#Top)
1380
1381 <a name="Handling Synchronous Responses"></a>
1382
1383 #### Handling Synchronous Responses
1384
1385 In the simplest case, you can wait for a response, potentially forever. Typically, you should handle both a valid response and an exception:
1386
1387 HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
1388
1389 try {
1390 HttpResponse response1 = httpClient.apply(request).apply();
1391 } catch (Exception e) {
1392 ...
1393 }
1394
1395 [Top](#Top)
1396
1397 <a name="Handling Synchronous Responses With Timeouts"></a>
1398
1399 #### Handling Synchronous Responses With Timeouts
1400
1401 To avoid waiting forever for a response, you can specify a duration, which throws an exception if the duration expires. The following example sets a duration of 1 second:
1402
1403 try {
1404 HttpResponse response2 = httpClient.apply(request).apply(
1405 new Duration(TimeUnit.SECONDS.toNanos(1)));
1406 } catch (Exception e) {
1407 ...
1408 }
1409
1410 [Top](#Top)
1411
1412 <a name="Handling Synchronous Responses With Exception Handling"></a>
1413
1414 #### Handling Synchronous Responses With Exception Handling
1415
1416 Use the `Try` and `Throw` classes in `com.twitter.util` to implement a more general approach to exception handling for synchronous responses. In addition to specifying a timeout duration, which can throw an exception, other exceptions can also be thrown.
1417
1418 Try<HttpResponse> responseTry = httpClient.apply(request).get(
1419 new Duration(TimeUnit.SECONDS.toNanos(1)));
1420 if (responseTry.isReturn()) {
1421 // Cool, I have a response! Get it and do something
1422 HttpResponse response3 = responseTry.get();
1423 ...
1424 } else {
1425 // Throw an exception
1426 Throwable throwable = ((Throw)responseTry).e();
1427 System.out.println("Exception thrown by client: " + throwable);
1428 }
1429
1430 **Note:** You must call the request's `get` method instead of the `apply` method to retrieve the `Try` object.
1431
1432 [Top](#Top)
1433
1434 <a name="Handling Asynchronous Responses"></a>
1435
1436 #### Handling Asynchronous Responses
1437
1438 To handle asynchronous responses, you add a `FutureEventListener` to listen for a response. Finagle invokes the `onSuccess` method when a response arrives or invokes `onFailure` for an exception:
1439
1440 httpClient.apply(request).addEventListener(new FutureEventListener<HttpResponse>() {
1441 @Override
1442 public void onSuccess(HttpResponse response4) {
1443 // Cool, I have a response, do something with it!
1444 ...
1445 }
1446
1447 @Override
1448 public void onFailure(Throwable throwable) {
1449 System.out.println("Exception thrown by client: " + throwable);
1450 }
1451 });
1452 }
1453 }
1454
1455 [Top](#Top)
1456
1457 <a name="Implementing a Pool for Blocking Operations in Java"></a>
1458
1459 ### Implementing a Thread Pool for Blocking Operations in Java
1460
1461 To prevent blocking operations from executing on the main Finagle thread, you must wrap the blocking operation in a Scala closure and execute the closure on the Java thread that you create. Typically, your Java thread is part of a thread pool. The following sections show how to wrap your blocking operation, set up a thread pool, and execute the blocking operation on a thread in your pool:
1462
1463 * <a href="#Wrapping the Blocking Operation">Wrapping the Blocking Operation</a>
1464 * <a href="#Setting Up Your Thread Pool">Setting Up Your Thread Pool</a>
1465 * <a href="#Invoking the Blocking Operation">Invoking the Blocking Operation</a>
1466
1467 **Note:** Jakob Homan provides an example implementation of a thread pool that executes Scala closures on <a href="https://github.com/jghoman/finagle-java-example">GitHub</a>.
1468
1469 [Top](#Top)
1470
1471 <a name="Wrapping the Blocking Operation"></a>
1472
1473 #### Wrapping the Blocking Operation
1474
1475 The `Util` project contains a `Function0` class that represents a Scala closure. You can override the `apply` method to wrap your blocking operation:
1476
1477 public static class BlockingOperation extends com.twitter.util.Function0<Integer> {
1478 public Integer apply() {
1479 // Implement your blocking operation here
1480 ...
1481 }
1482 }
1483
1484 [Top](#Top)
1485
1486 <a name="Setting Up Your Thread Pool"></a>
1487
1488 #### Setting Up Your Thread Pool
1489
1490 The following example shows a Thrift server that places the blocking operation defined in the `Future0` object's `apply` method in the Java thread pool, where it will eventually execute and return a result:
1491
1492 public static class HelloServer implements Hello.ServiceIface {
1493 ExecutorService pool = Executors.newFixedThreadPool(4); // Java thread pool
1494 ExecutorServiceFuturePool futurePool = new ExecutorServiceFuturePool(threads); // Java Future thread pool
1495
1496 public Future<Integer> blockingOperation() {
1497 Function0<Integer> blockingWork = new BlockingOperation();
1498 return futurePool.apply(blockingWork);
1499 }
1500
1501 public static void main(String[] args) {
1502 Hello.ServiceIface processor = new Hello.ServiceIface();
1503
1504 ServerBuilder.safeBuild(
1505 new Hello.Service(processor, new TBinaryProtocol.Factory()),
1506 ServerBuilder.get()
1507 .name("HelloService")
1508 .codec(ThriftServerFramedCodec.get())
1509 .bindTo(new InetSocketAddress(8080))
1510 );
1511 )
1512 )
1513 )
1514
1515 [Top](#Top)
1516
1517 <a name="Invoking the Blocking Operation"></a>
1518
1519 #### Invoking the Blocking Operation
1520
1521 To invoke the blocking operation, you call the method that wraps your blocking operation and add an event listener that waits for either success or failure:
1522
1523 Service<ThriftClientRequest, byte[]> client = ClientBuilder.safeBuild(ClientBuilder.get()
1524 .hosts(new InetSocketAddress(8080))
1525 .codec(new ThriftClientFramedCodecFactory())
1526 .hostConnectionLimit(100)); // Must be more than 1 to enable parallel execution
1527
1528 Hello.ServiceIface client =
1529 new Hello.ServiceToClient(client, new TBinaryProtocol.Factory());
1530
1531 client.blockingOperation().addEventListener(new FutureEventListener<Integer>() {
1532 public void onSuccess(Integer i) {
1533 System.out.println(i);
1534 }
1535
1536 public void onFailure(Throwable t) {
1537 System.out.println("Exception! ", t.toString());
1538 });
1539
1540 [Top](#Top)
1541
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1542 <a name="Additional Samples"></a>
1543
1544 ## Additional Samples
1545
1546 * [Echo](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/echo) - A simple echo client and server using a newline-delimited protocol. Illustrates the basics of asynchronous control-flow.
1547 * [Http](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/http) - An advanced HTTP client and server that illustrates the use of Filters to compositionally organize your code. Filters are used here to isolate authentication and error handling concerns.
1548 * [Memcached Proxy](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/memcachedproxy) - A simple proxy supporting the Memcached protocol.
1549 * [Stream](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/stream) - An illustration of Channels, the abstraction for Streaming protocols.
1550 * [Spritzer 2 Kestrel](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/spritzer2kestrel) - An illustration of Channels, the abstraction for Streaming protocols. Here the Twitter Firehose is "piped" into a Kestrel message queue, illustrating some of the compositionality of Channels.
1551 * [Stress](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/stress) - A high-throughput HTTP client for driving stressful traffic to an HTTP server. Illustrates more advanced asynchronous control-flow.
1552 * [Thrift](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/thrift) - A simple client and server for a Thrift protocol.
97aaeff @kevinoliver [split] Adding documentation
kevinoliver authored
1553 * [Kestrel Client](https://github.com/twitter/finagle/tree/master/finagle-example/src/main/scala/com/twitter/finagle/example/kestrel) - A client for doing reliable reads from one or more Kestrel servers.
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1554
1555 [Top](#Top)
1556
1557 <a name="API Reference Documentation"></a>
1558
1559 ## API Reference Documentation
1560
d1ba060 @mariusae [split] finagle·doc: fix up API ref links.
mariusae authored
1561 * [Builders](http://twitter.github.com/finagle/api/finagle-core/com/twitter/finagle/builder/package.html)
1562 * [Service](http://twitter.github.com/finagle/api/finagle-core/com/twitter/finagle/Service.html)
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1563 * [Future](http://twitter.github.com/util/util-core/target/site/doc/main/api/com/twitter/util/Future.html)
d1ba060 @mariusae [split] finagle·doc: fix up API ref links.
mariusae authored
1564 * [Complete Core Project Scaladoc](http://twitter.github.com/finagle/api/finagle-core/)
63e1467 @mccue Revised Java pattern in README.md for handling async server requests …
mccue authored
1565 * [Kestrel](http://twitter.github.com/finagle/api/finagle-kestrel/index.html)
1566 * [Memcached](http://twitter.github.com/finagle/api/finagle-memcached/index.html)
1567 * [Ostrich 4](http://twitter.github.com/finagle/api/finagle-ostrich4/index.html)
1568 * [ServerSets](http://twitter.github.com/finagle/api/finagle-serversets/index.html)
1569 * [Stream](http://twitter.github.com/finagle/api/finagle-stream/index.html)
1570 * [Thrift](http://twitter.github.com/finagle/api/finagle-thrift/index.html)
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1571 * [Complete Util Project Scaladoc](http://twitter.github.com/util/util-core/target/site/doc/main/api/)
1572
c29958d @mccue Changed occurrences of RCP to RPC
mccue authored
1573 For the software revision history, see the [Finagle change log](https://github.com/twitter/finagle/blob/master/ChangeLog).
1574 For additional information about Finagle, see the [Finagle homepage](http://twitter.github.com/finagle/).
d1ba060 @mariusae [split] finagle·doc: fix up API ref links.
mariusae authored
1575
f74d889 @mccue Changing contents of README.md to Finagle Developer Guide
mccue authored
1576 [Top](#Top)
d3f0050 @mariusae include changelog in README
mariusae authored
1577
Something went wrong with that request. Please try again.