system integration with akka and apache camel

56
Connecting Akka to the Rest of the World System integration with Akka and Apache Camel by Martin Krasser

Upload: krasserm

Post on 06-May-2015

14.687 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: System Integration with Akka and Apache Camel

Connecting Akka to theRest of the World

System integration with

Akka and Apache Camel

by Martin Krasser

Page 2: System Integration with Akka and Apache Camel

About me• Freelance software engineer, architect

– eHealth application integration (Java, Scala, Groovy)– Bioinformatics, Cheminformatics (C++, Java)– …

• Open source committer– Akka– Camel– Scalaz-Camel– …

• Java since 1998• Scala since 2009

• Twitter: @mrt1nz

Page 3: System Integration with Akka and Apache Camel

Overview

• Introduction– Camel– Akka

• Akka-Camel integration– Consumer actors– Producer actors– Actor components

• Comparison– Camel routes– Akka-Camel routes– Scalaz-Camel routes

Page 4: System Integration with Akka and Apache Camel

Apache Camel

• Integration framework written in Java– Open source, Apache 2 license– http://camel.apache.org

• Enterprise Integration Patterns (EIP)– G. Hohpe, B. Woolf

• Domain-specific language (DSL)– Internal: Java, Scala– External: XML/Spring

• Pluggable protocol and API bindings– HTTP, FTP, JMS, File … and approx. 100 more– Camel “components” http://camel.apache.org/components.html

Page 5: System Integration with Akka and Apache Camel

Apache Camel

• Usage in Scala applications

– Camel Java/Scala DSL• http://camel.apache.org

– Akka-Camel integration module• http://akka.io/docs/akka-modules/1.1.2/modules/camel.html

– Scalaz-Camel DSL• https://github.com/krasserm/scalaz-camel

Page 6: System Integration with Akka and Apache Camel

Apache Camel

• Architecture

Page 7: System Integration with Akka and Apache Camel

Apache Camel

• Routing example

JMSEndpoint

HTTPEndpoint

Filter

D D

HTTP

http://example.org/docs

jms:queue:docs

Java DSL:

from("jms:queue:docs") .filter().xpath("/person[@name='Jon']") .to("http:example.org/docs");

Scala DSL:

"jms:queue:docs" when(_.in == "…") to("http:example.org/docs");

Page 8: System Integration with Akka and Apache Camel

Apache Camel

• Messaging endpoints– Configured via endpoint URI

• "jms:queue:docs"• "http://example.org/docs"• …

– Endpoint consumer: from(uri)– Endpoint producer: to(uri)

• Message processors– Configured via fluent API

• filter().xpath("…")• transform(body().append("…"))• …

– Custom Java/Scala code (Processor interface)

Page 9: System Integration with Akka and Apache Camel

Akka

• Platform for event-driven, scalable and fault-tolerant architectures on the JVM

• Concurrency– Actors, agents, dataflow, STM

• Scalability– Remote actors, cluster membership

• Fault tolerance– Local and remote actor supervision

CoreServices

Page 10: System Integration with Akka and Apache Camel

Akka• Add-on modules

– akka-camel • Camel integration (untyped actors)

– akka-camel-typed• Camel integration (typed actors)

– akka-kernel • Microkernel

– akka-scalaz• Scalaz support

– akka-spring • Spring integration

– …

Page 11: System Integration with Akka and Apache Camel

Akka• Actor model

– Mathematical model of concurrent computation– Carl Hewitt, 1973

• Akka actor– Encapsulates state– Encapsulates behavior– Exchanges messages– Mailbox– Event-driven– Single-threaded

• API– Scala– Java

Page 12: System Integration with Akka and Apache Camel

Akka

• Actor model benefits– Easier to reason about

– Raised abstraction level– Easier to avoid

• Race conditions

• Dead locks

• Starvation

• Live locks

Page 13: System Integration with Akka and Apache Camel

Akka Actors

• Receive messagesimport akka.actor.Actor

// actor definitionclass ExampleActor extends Actor { def receive = { case "test" => … case _ => … }}

// create actor reference (ActorRef)val actor = Actor.actorOf[ExampleActor]

// start actoractor.start

Page 14: System Integration with Akka and Apache Camel

Akka Actors

• Send messages

– Fire-Forget

actor ! "test"

Page 15: System Integration with Akka and Apache Camel

Akka Actors

• Send messages

– Send-And-Receive-Eventually

actor !! "test" match { case Some(result) => … // process result case None => … // timeout}

uses Future under the hood (with timeout)

Page 16: System Integration with Akka and Apache Camel

Akka Actors

• Send messages

– Send-And-Receive-Future

val future = actor !!! "test"future.awaitval result = future.get

returns Future directly

Page 17: System Integration with Akka and Apache Camel

Overview

• Introduction– Camel– Akka

• Akka-Camel integration– Consumer actors– Producer actors– Actor components

• Comparison– Camel routes– Akka-Camel routes– Scalaz-Camel routes

Page 18: System Integration with Akka and Apache Camel

Akka-Camel Integration

• Exchange messages with Akka actors via– HTTP, FTP, JMS, File … and approx. 100 more– Any Camel component can be used (pluggable)

• Integration layer of Akka– Consumer actors: receive message from Camel endpoints– Producer actors: produce messages to Camel endpoints– Message exchange patterns (MEPs): in-out and in-only

• Leverages Camel’s asynchronous routing engine– Asynchronous completion of message exchange– No threads blocked waiting for response messages, for example

Page 19: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – TCP consumer•

– Camel component: camel-mina– MEP: in-out

import akka.actor._import akka.camel._

class TcpConsumer extends Actor with Consumer { def endpointUri = "mina:tcp://localhost:6200?textline=true" def receive = { case Message(body, headers) => { self.reply("received %s" format body) } }}

Page 20: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – TCP consumer activation

– Asynchronous activation of consumer endpoint

import akka.actor._import akka.camel._

// Consumer actors require a running CamelServiceCamelServiceManager.startCamelService

// Activate TCP endpoint (asynchronously)Actor.actorOf[TcpConsumer].start

Page 21: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – TCP consumer activation

– Wait for endpoint activation

– Useful for testing purposes

import akka.actor._import akka.camel._

// Consumer actors require a running CamelServiceval service = CamelServiceManager.startCamelService

// Wait for TCP endpoint activationservice.awaitEndpointActivation(1) { Actor.actorOf[TcpConsumer].start}

Page 22: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – TCP consumer deactivationimport akka.actor._import akka.camel._

val service: CamelService = …val tcpConsumer: ActorRef = …

// deactivate TCP endpoint (asynchronously)tcpConsumer.stop

// … or wait for TCP endpoint deactivationservice.awaitEndpointDeactivation(1) { tcpConsumer.stop}

Page 23: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – HTTP consumer

– Camel component: camel-jetty– MEP: in-out– Jetty continuations used internally– Camel type converter (msg.bodyAs[…])

class HttpConsumer extends Actor with Consumer { def endpointUri = "jetty:http://localhost:8080/example" def receive = { case msg: Message => { self.reply("received %s" format msg.bodyAs[String]) } }}

Page 24: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – JMS consumer

– Camel component: camel-jms

– MEP: in-only

class JMSConsumer extends Actor with Consumer { def endpointUri = "jms:queue:example" def receive = { case Message(body, headers) => ... }}

Page 25: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – IMAP consumer

– Camel component: camel-mail– MEP: in-only

class MailConsumer extends Actor with Consumer { def endpointUri = "imap://[email protected]?password=secret" def receive = { case Message(body, headers) => ... }}

Page 26: System Integration with Akka and Apache Camel

Consumer Actors

• Basic example – Scheduled consumer

– Camel component: camel-quartz– MEP: in-only

class ScheduledConsumer extends Actor with Consumer { def endpointUri = "quartz://example?cron=0/2+*+*+*+*+?" def receive = { case tick => ... }}

Page 27: System Integration with Akka and Apache Camel

Consumer Actors

• Acknowledgements

– Camel component: camel-file– MEP: in-only– Application-level acknowledgement (Ack)

import akka.camel.Ack...

class FileConsumer extends Actor with Consumer { override def autoack = false // default is true def endpointUri = "file:messages/in?delete=true" def receive = { case Message(body, headers) => { // ... self.reply(Ack) // delete consumed file } }}

Page 28: System Integration with Akka and Apache Camel

Consumer Actors

• Failure replies

– Application-level negative acknowledgement (Failure)– Redelivery works also with JMS endpoints, for example– Failure replies can also be used with in-out MEP

import akka.camel.Failure...

class FileConsumer extends Actor with Consumer { override def autoack = false // default is true def endpointUri = "file:messages/in?delete=true" def receive = { case Message(body, headers) => { // ... self.reply(Failure(reason)) // redeliver file } }}

Page 29: System Integration with Akka and Apache Camel

Consumer Actors

• Failure replies

– Should not be made within receive

– Let consumer actors crash (on Exception)

– Use a supervisor for failure replies

Page 30: System Integration with Akka and Apache Camel

Consumer Actors• Supervised consumerclass SupervisedFileConsumer extends Actor with Consumer { override def autoack = false def endpointUri = "file:messages/in?delete=true" def receive = { case Message(body, headers) => { // if exception thrown: actor is restarted or stopped // else self.reply(Ack) // delete file } } override def preRestart(reason: scala.Throwable) { self.reply_?(Failure(reason)) // redeliver file } override def postStop() { self.reply_?(Failure(…)) // or Ack to delete file }}

Page 31: System Integration with Akka and Apache Camel

Consumer Actors• Supervised consumer

– Restart on any Exception– 5 restart attempts within 10 seconds

import akka.actor._ import akka.config.Supervision._

// Create consumer actor referenceval consumer = Actor.actorOf[new SupervisedFileConsumer]

// Create supervisor for consumer actorval supervisor = Supervisor( SupervisorConfig( OneForOneStrategy( List(classOf[Exception]), 5, 10000), Supervise(consumer, Permanent) :: Nil))

Page 32: System Integration with Akka and Apache Camel

Consumer Actors

• Simplified failure reporting– override def blocking = true

– Pros• No need for setting up a supervisor• No need to catch exception within receive• No need to self.reply(Failure(…))

– Cons• Endpoint communicates with actor via !!• Thread blocked waiting for Ack

Page 33: System Integration with Akka and Apache Camel

Consumer Actors

• Simplified failure reportingclass FileConsumer extends Actor with Consumer { override def blocking = true override def autoack = false def endpointUri = "file:messages/in?delete=true" def receive = { case Message(body, headers) => { // if exception thrown: endpoint receives it // else self.reply(Ack) // delete file } }}

Page 34: System Integration with Akka and Apache Camel

Typed Consumer Actors

• Basic example – HTTP/JMS consumerimport akka.actor._import akka.camel._import org.apache.camel.{Body, Header}

trait TypedConsumer { @consume("jetty:http://localhost:8080/example") // in-out def foo(s: String): String

@consume("jms:queue:example") // in-only def bar (@Body s: String, @Header("priority") p: Integer) : Unit}

class TypedConsumerImpl extends TypedActor with TypedConsumer { def foo(s: String) = "received %s" format s def bar(s: String, p: Integer) = println("received %s (priority = %d)" format(s, p))}

Page 35: System Integration with Akka and Apache Camel

Typed Consumer Actors

• Annotations

– Consumer endpoints•@consume(endpointURI)

– Parameter bindings•@Body•@Header•…

Page 36: System Integration with Akka and Apache Camel

Typed Consumer Actors

• Basic example – HTTP/JMS consumer activationimport akka.actor._import akka.camel._

val service = CamelServiceManager.startCamelService

// Activate HTTP and JMS endpoints (asynchronously)TypedActor.newInstance( classOf[TypedConsumer], classOf[TypedConsumerImpl])

// … or wait for HTTP and JMS endpoint activationservice.awaitEndpointActivation(2) { TypedActor.newInstance( classOf[TypedConsumer], classOf[TypedConsumerImpl]) }

Page 37: System Integration with Akka and Apache Camel

Producer Actors

• Basic example – HTTP producer

– Camel component: camel-jetty

– MEP: in-out– receive inherited from Producer trait– Jetty’s async HTTP client used internally

import akka.actor._import akka.camel._

class HttpProducer extends Actor with Producer { def endpointUri = "jetty:http://localhost:8080/example"}

Page 38: System Integration with Akka and Apache Camel

Producer Actors

• Basic example – HTTP producer activationimport akka.actor._import akka.camel._

// Producer actors require an initialized CamelContextCamelServiceManager.startCamelService

// activate producer actorval producer = Actor.actorOf[HttpProducer].start

// POST test message to http://localhost:8080/exampleproducer !! "test" match { case Some(m: Message) => … case Some(f: Failure) => … case None => …} // ! and !!! can also be used

Page 39: System Integration with Akka and Apache Camel

Producer Actors

• Basic example – JMS producer

– Camel component: camel-jms– MEP: in-only

class JmsProducer extends Actor with Producer { def endpointUri = "jms:queue:example" override def oneway = true}

Page 40: System Integration with Akka and Apache Camel

Producer Actors

• oneway = false (default)– Initiates an in-out ME with endpoint– Replies result to initial sender

• oneway = true– Initiates an in-only ME with endpoint– No reply to sender

• receiveAfterProduce– Change default reply behaviour

Page 41: System Integration with Akka and Apache Camel

Producer Actors

• Custom replies

class JmsProducer extends Actor with Producer { def endpointUri = "jms:queue:example" override def oneway = true override def receiveAfterProduce = { case m: Message => self.reply("enqueue succeeded") case f: Failure => self.reply("enqueue failed") } }

Page 42: System Integration with Akka and Apache Camel

Producer Actors

• Forward results

– Chaining of producer actors (pipelines)– Related: Future composition

class HttpProducer extends Actor with Producer { val target: ActorRef = … def endpointUri = "jetty:http://localhost:8080/example" override def receiveAfterProduce = { case msg => target forward msg } }

Page 43: System Integration with Akka and Apache Camel

Producer Actors

• Future composition

– Producer pipeline

val producer1 = Actor.actorOf[HttpProducer1].startval producer2 = Actor.actorOf[HttpProducer2].start

// monadic future composition (non-blocking)val future = for { m1: Message <- producer1 !!! Message("test") m2: Message <- producer2 !!! m1} yield m2

// blocks until result is availableval result: Message = future.get

Page 44: System Integration with Akka and Apache Camel

Actor Components

• Are Camel components– Can be used in any Camel route

• actor Camel component– Send messages to untyped actors– Provided by akka-camel module

• typed-actor Camel component– Send messages to typed actors– Provided by akka-camel-typed module– Extension of Camel’s bean component

• Used by akka-camel internally– Routes to consumer actors

Page 45: System Integration with Akka and Apache Camel

Actor Components

• actor endpoint URI– actor:uuid:[<actor-uuid>][?<params>]

• Parameters– autoack: Boolean

• System or application-level acknowledgements– blocking: Boolean

• Use ! or !! for sending messages to actor

• Supported message headers– CamelActorIdentifier

• Dynamic routing to actors

Page 46: System Integration with Akka and Apache Camel

Actor Components

• Example

– actor receives messages of type Message

import akka.actor._

// can be any actor (no need for Consumer)val actor = Actor.actorOf[SomeActor].start

// ...

// Camel route from JMS endpoint to actorfrom("jms:queue:example") .to("actor:uuid:%s?autoack=false" format actor.uuid)

Page 47: System Integration with Akka and Apache Camel

Overview

• Introduction– Camel– Akka

• Akka-Camel integration– Consumer actors– Producer actors– Actor components

• Comparison– Camel routes– Akka-Camel routes– Scalaz-Camel routes

Page 48: System Integration with Akka and Apache Camel

Comparison

• Criteria– Connectivity– Message processing– Route composition– Other

• High-level• Incomplete

Page 49: System Integration with Akka and Apache Camel

Camel Routes

• Connectivity– Camel components/endpoints

• Message processing– Processor interface

• Predefined processors (all known EIPs)• Custom processors

– Concurrent execution of Processor instances– Mutable messages

Page 50: System Integration with Akka and Apache Camel

Camel Routes

• Route composition– Camel DSL (Java, Scala, XML)

• Other– No built-in mechanism for distributing routes (except

via endpoints)– Distribution addressed by ServiceMix and

FuseSource Fabric, for example

Page 51: System Integration with Akka and Apache Camel

Akka-Camel Routes

• Connectivity– Camel components/endpoints managed by

• Consumer actors• Producer actors

• Message processing– Actor

• Predefined (a few in akka.actor.routing)• Custom

– Sequential execution of actor instance– Immutable messages

Page 52: System Integration with Akka and Apache Camel

Akka-Camel Routes

• Route composition– Wiring actors (low-level)– Future composition– …– No integration DSL (yet)

• Other– Easy to implementing stateful EIPs (aggregator,

resequencer …)– Strong built-in mechanisms for distribution, scalability

and fault-tolerance– Basis for a distributed and scalable Enterprise Service

Bus (?)

Page 53: System Integration with Akka and Apache Camel

Scalaz-Camel Routes

• Connectivity– Camel components/endpoints

• Message processing– Scala functions

• Predefined (some EIPs)• Custom

– Concurrent execution– Immutable messages

Page 54: System Integration with Akka and Apache Camel

Scalaz-Camel Routes

• Route composition– Based on functional programming concepts

• Message processors chained via Kleisli composition (>=>)

– Continuation-based approach• scala.Responder used as continuation monad

– Direct-style DSL

• Other – Configurable concurrency strategies– Camel processors can be re-used– Akka integration

Page 55: System Integration with Akka and Apache Camel

Scalaz-Camel Routes

• Example

– Details at https://github.com/krasserm/scalaz-camel

// custom message processorval validate: MessageProcessor = ...

// Kleisli composition of route (+ implicit conversions)val vroute = validate >=> oneway >=> to("jms:queue:valid") >=> { m: Message => m.setBody("order accepted") }

// consume messages via HTTP and error handling routesfrom(jetty:http://localhost:8080/orders) attempt { vroute } fallback { case e: ValidationException => { m: Message => ... } >=> failWith(e) case _ => ...}

Page 56: System Integration with Akka and Apache Camel

THANK YOU!