executed • AIO: should definitely be used, but is not enough! What is Asynchronous IO (AIO)? // Java 8 Asynchronous IO example CompletionStage<Response> someResponse = makeRequest(); CompletionStage<MyModel> futureModel = someResponse.thenApply(response -> { MyModel model = decode(response.getBody()); return model; });
architecture perhaps? ◦ Load balancers ◦ Caching sprinkled everywhere ◦ Various other optimizations ◦ Most of the time added in retrospect … ◦ … which leads to complex and inherently fragile architectures • So what can we do instead? Take two.
messaging/CQRS/Event Sourcing ◦ and timeouts for service calls • In other words you want to use a combination of asynchronous communication and asynchronous IO
as a synchronous communication protocol ◦ Client Request leads to Service Response • Can be used for asynchronous messaging ◦ HTTP 202 - Accepted ◦ HTTP 204 - No Content • REST in itself is not a problem but it can lead to an architecture that is...
our go-to but… ◦ Don’t just do a 1:1 service/interface replacement • Instead… ◦ Design for an asynchronous architecture • Pro-tip: Watch Ben Christensen’s “Don’t build a distributed Monolith” talk from Microservices Practitioner Summit 2016* *Lagom will soon support dependency on Swagger as an alternative to direct binary dependencies as suggested in Christensen’s talk
• Be autonomous - do not rely on other services • Own its data • Look at DDD for inspiration ◦ Bounded Context ◦ Ubiquitous Language ◦ Aggregate Root, Entity, Value Object, etc.
Services are asynchronous ◦ Intra-service communication handled for you ◦ Streaming out of the box ◦ Built in resilience ◦ Developer friendly ◦ Seamless deployment
{ ServiceCall<NotUsed, String, String> sayHello(); default Descriptor descriptor() { return named("hello").with( call(sayHello()) ); } } All code examples can be studied in full format (including imports) in the Lagom documentation
CompletionStage<Response> invoke(Id id, Request request); } • ServiceCall takes 3 params: Id, Request and Response ◦ Id: extracted from incoming identifier (usually in the path of a REST request) ◦ Request: type of incoming request message (e.g. String) ◦ Response: type of outgoing response message (e.g. String) • CompletionStage “A stage of a possibly asynchronous computation, that performs an action or computes a value when another CompletionStage completes”
with one call sayHello • Lagom will map sayHello() call to a POST request on a static path of /sayHello, with text/plain request and response bodies • All of the above is, of course, configurable...
can be represented by a Java object • These type of messages get buffered and parsed (e.g. as JSON) • If both types are strict it is a traditional request response call (albeit in an asynchronous fashion if between services) • Strict messages means that the request/response is loaded in memory before processing logic is executed
default Descriptor descriptor() { return named("clock").with( pathCall("/tick/:interval", tick()) ); } • A streamed message is of type Source (an Akka streams API) • It allows asynchronous streaming and handling of messages • Lagom will select transport protocol (typically WebSockets) • To achieve the above is quite tricky if you roll your own...
value may not yet be computed = you can’t interact with it immediately ◦ Instead you attach callbacks: thenApply and thenCompose ◦ Callbacks allow your code to be asynchronous - not waiting/holding thread ◦ completedFuture can be used for values that are completed immediately public class HelloServiceImpl implements HelloService { public ServiceCall<NotUsed, String, String> sayHello() { return (id, name) -> completedFuture("Hello " + name); } }
(immutable facts) • Query (read) data on “the other side” • Some Advantages: ◦ No need for ORM ◦ Easy to test and debug ◦ Append only can enable great performance • Yes, Lagom can still be used without using ES* *Only ES and Cassandra is supported out of the box though
can be accessed from anywhere in the cluster, is run by an actor and the state is persistent using ES • Corresponds to Aggregate Root in DDD • For any id there will only be one entity • All you have to do is to extend PersistentEntity<Command, Event, State> and override some methods and voila, ES!
Language, e.g. “SELECT id, title FROM postsummary;” • Updating read side: extend CassandraReadSideProcessor • Streaming of events: use the eventStream method of the PersistentEntityRegistry class
runAll [info] ... [info] Service helloworld-impl listening for HTTP on 0:0:0:0:0:0:0:0:23966 [info] Service hellostream-impl listening for HTTP on 0:0:0:0:0:0:0:0:27462 (Services started, use Ctrl+D to stop and go back to the console...) Behind the scenes: • An embedded Service Locator is started • A Cassandra server is started • Your services start and register with the Service Locator
https://lightbend.com/lagom • Sample application https://www.lightbend.com/activator/template/lagom- java-chirper • Read Jonas Bonér's free book Reactive Services Architecture ◦ https://lightbend.com/reactive-microservices-architecture • Great presentation by Greg Young on why you should use ES ◦ https://www.youtube.com/watch?v=JHGkaShoyNs • Please help us improve Lagom: ◦ https://github.com/lagom/lagom