Netty, which is used within Finagle, uses a pipeline of "handlers" to sequentially process in and out bound data. Netty examples, and included libraries, show various handlers used for things such as authentication, protocol codecs, and the actual business logic of the service.
Finagle appears to take the handler concept, and instead directly offer API users codecs, filters, and services. While these have varying signatures, new users of Finagle are left with the tasks of deciding which to use in order to implement each portion of their overall server. Instead of merely deciding where to break the chain up into various Netty handlers, they now need to decide which portion should be part of a codec, versus any filters, versus the singular service at the end of the chain. In sum, although Finagle is a higher-level library than Netty, and should make the task of building the service easier, the API user may have more choices to make.
What are the key decision points, and pros/cons, for placing a particular portion of the processing stream into a codec vs. a filter vs. the singular service? If there is a possibility that the pipeline could be extended further, should the service logic be placed into a filter instead, with a "noop" service at the end of the pipeline? Given the flexibility in ordering filters (as handlers in the pipeline), versus the singular codec on one end and service on the other end, why shouldn't "everything" be a filter?
I don't think it should be a decision between codec or filter. Codecs would rather get wrapped in filters.
As for decision logic, where to place it, would depend on the decisions that has to be made. Business decisions should go with your business logic, while some decisions like routing, load balancing, certain types of access control, etc. could fit in well as a filter.
Services are typically sit at the end of the line, and Finagle with it's filters will get you there.
Don't know if this makes sense?
Just step away from the technical detail for a moment, and look at the logic. What should be responsible for what, and then get the technology to fit your design. Don't bend your design too much to fit the technology.
By the way, I've implemented a gateway server on top of Finagle, and I must say: It's a nice library to work with.
I don't know what you are trying to build, but have a look at possible alternatives also: Spray, Blueeyes, Unfiltered, Play-Mini, etc. It may help you get a better understanding of what goes where.
Finagle and Netty are structured quite differently.
Services, Filters, and codecs are actually quite orthogonal concepts. Let me try & explain. As a user -- ie. not an implementor of a codec -- you should only need to know about services and filters.
First, a codec is responsible for turning a stream of bytes into a discrete requests or responses. For example, the HTTP codec reads the bytestream, and produces
HttpRequest
orHttpResponse
objects.A
Service
is an object that, given a request, produces aFuture
of a reply -- it’s a simple function (and indeed it extendsFunction
). The interesting thing about services is that they are symmetric. A client uses a service, a server provides one. The important thing about services is that (1) they operate over discrete requests and responses, and (2) they match requests to responses - all of which is implied by its type. This is why we call finagle an “RPC” system - request/response pairs are the defining characteristic of RPCs.So, we have Services, but it's useful and important to have modify Service behavior independently of the service itself. For example, we might want to provide timeout functionality, or retries. This is what
Filter
s do. They provide a service independent method of modifying Service behavior. This enhanced modularity and reuse. For example, timeouts in finagle are implemented as a filter, and can be applied to any service.You can find more details about services & filters in the Scala School.
*
So, let’s contrast this to Netty’s handlers. These are generic event handlers, that are also stackable. You can do many similar things with them, but the underlying model is a stream of events that are attached to a connection. This makes it more difficult to write generic modules (eg. to implement retries, timeouts, failure accrual, tracing, exception reporting, etc..) because you cannot make many assumptions about the pipeline you’re operating with.
Netty pipelines also conflate the protocol implementation with application handlers. Finagle cleanly separates the two, and modularity is enhanced because of it.
Netty is a wonderful set of abstractions, but for RPC servers, finagle offers greater modularity and composability.
*
Summarizing crudely you could say that Netty is “stream oriented” while finagle is “service oriented”. This is an important distinction, and it's what allows us to implement robust RPC services in a modular manner. For example, connection pooling and load balancing - crucially important to RPC clients - fall out naturally from the service model, but doesn’t fit in the stream model.