Building reliable software in a multi-core world Akka Concurrency artima Derek Wyatt Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Akka Concurrency PrePrint™ Edition Cover · Overview · Contents · Discuss · Suggest · Glossary · Index iii Thank you for purchasing the PrePrint™ Edition of Akka Concurrency A PrePrint™ is a work-in-progress, a book that has not yet been fully written, reviewed, edited, or formatted We are publishing this book as a PrePrint™ for two main reasons First, even though this book is not quite finished, the information contained in its pages can already provide value to many readers Second, we hope to get reports of errata and suggestions for improvement from those readers while we still have time to incorporate them into the first printing As a PrePrint™ customer, you’ll be able to download new PrePrint™ versions from Artima as the book evolves, as well as the final PDF of the book once finished You’ll have access to the book’s content prior to its print publication, and can participate in its creation by submitting feedback Please submit by clicking on the Suggest link at the bottom of each page Thanks for your participation We hope you find the book useful and enjoyable Bill Venners President, Artima, Inc Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Akka Concurrency PrePrint™ Edition Derek Wyatt artima A RTIMA P RESS WALNUT C REEK , C ALIFORNIA Cover · Overview · Contents · Discuss · Suggest · Glossary · Index v Akka Concurrency First Edition PrePrint™ Edition Version February 15, 2013 Derek Wyatt is a Software Architect and Developer specializing in large-scale, real-time applications for the World Wide Web Artima Press is an imprint of Artima, Inc P.O Box 305, Walnut Creek, California 94597 Copyright © 2012-2013 Derek Wyatt All rights reserved First edition published as PrePrint™ eBook 2012 Version published February 15, 2013 Build date of this impression February 15, 2013 Produced in the United States of America No part of this publication may be reproduced, modified, distributed, stored in a retrieval system, republished, displayed, or performed, for commercial or noncommercial purposes or for compensation of any kind without prior written permission from Artima, Inc This PDF eBook is prepared exclusively for its purchaser The purchaser of this PrePrint Edition may download, view on-screen, and print it for personal, noncommercial use only, provided that all copies include the following notice in a clearly visible position: “Copyright © 2012 Derek Wyatt All rights reserved.” The purchaser may store one electronic copy and one electronic backup, and may print one copy, for personal, noncommercial use only All information and materials in this book are provided “as is” and without warranty of any kind The term “Artima” and the Artima logo are trademarks or registered trademarks of Artima, Inc All other company and/or product names may be trademarks or registered trademarks of their owners Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Overview Contents List of Figures Introduction Why Akka? Concurrency and Parallelism Setting Up Akka Akka Does Concurrency Actors Akka Testing Systems, Contexts, Paths, and Locations Supervision and DeathWatch Being Stateful 10 Routing Messages 11 Dispatchers and Mailboxes 12 Coding in the Future 13 Networking with IO 14 Going Multi-Node with Remote Actors 15 Sharing Data with Agents 16 Granular Concurrency with Dataflow 17 Patterns for Akka Programming 18 Antipatterns for Akka Programming 19 Growing Your App with Add-On Modules 20 Using Akka from Java 21 Now that You’re an Akka Coder Bibliography About the author Index Cover · Overview · Contents · Discuss · Suggest · Glossary · Index vii xiii xvi 23 32 57 60 88 126 151 176 225 275 307 322 369 379 414 429 438 469 482 491 509 511 512 513 Contents Contents vii List of Figures xiii Introduction xvi 23 24 26 26 28 31 Concurrency and Parallelism 2.1 Parallelism versus concurrency 2.2 A critical look at shared-state concurrency 2.3 Immutability 2.4 Conclusion 32 32 33 44 56 Setting Up Akka 3.1 Installation using the Typesafe stack 3.2 That’s it? 57 57 59 Akka Does Concurrency 4.1 The actor 4.2 The future 4.3 The other stuff 4.4 You grabbed the right toolkit 60 60 77 83 87 Why Akka? 1.1 Concurrent challenges 1.2 Akka is concurrency 1.3 Concurrency methodologies 1.4 The Akka concurrency toolkit 1.5 So, why Akka? Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Contents viii Actors 5.1 The components of an actor 5.2 Properties of an actor 5.3 How to talk to an actor 5.4 Creating actors 5.5 Actors in the clouds 5.6 Tying it together 5.7 How message sending really works 5.8 The ActorSystem runs the show 5.9 Conclusion 88 90 92 96 100 101 116 118 122 124 Akka Testing 6.1 Making changes to sbt 6.2 A bit of refactoring 6.3 Testing the EventSource 6.4 The interaction between ImplicitSender and testActor 6.5 TestKit, ActorSystem, and ScalaTest 6.6 Testing the altimeter 6.7 Akka’s other testing facilities 6.8 About test probes and the testActor 6.9 Chapter summary 126 126 127 129 133 134 139 146 148 150 Systems, Contexts, Paths, and Locations 7.1 The ActorSystem 7.2 Actor paths 7.3 Staffing the plane 7.4 The ActorContext 7.5 Relating the path, context, and system 7.6 Chapter summary 151 151 153 155 165 172 174 176 176 177 180 188 194 216 223 Supervision and DeathWatch 8.1 What makes actors fail? 8.2 The actor life cycle 8.3 What is a supervisor? 8.4 Watching for death 8.5 The plane that healed itself 8.6 Dead pilots 8.7 Chapter summary Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Contents Being Stateful 9.1 Changing behaviour 9.2 The stateful flight attendant 9.3 A better flyer 9.4 The naughty pilot 9.5 Some challenges 9.6 Testing FSMs 9.7 Testing the pilot 9.8 Chapter summary ix 225 225 230 237 258 269 270 272 273 10 Routing Messages 10.1 Routers are not actors 10.2 Akka’s standard routers 10.3 Routers and children 10.4 Routers on a plane 10.5 Magically appearing flight attendants 10.6 Sectioning off flight attendant territory 10.7 More you can with routers 10.8 With that said 10.9 Chapter summary 275 275 275 282 285 298 300 304 305 305 307 307 311 313 320 321 322 322 325 328 330 349 354 364 367 11 Dispatchers and Mailboxes 11.1 Dispatchers 11.2 Dispatcher tweaking 11.3 Mailboxes 11.4 When to choose a dispatching method 11.5 Chapter summary 12 Coding in the Future 12.1 What is the future? 12.2 Don’t wait for the future 12.3 Promises and futures 12.4 Functional futures 12.5 Side-effecting 12.6 Futures and actors 12.7 Plane futures 12.8 Chapter summary Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Contents x 13 Networking with IO 13.1 The plane’s Telnet server 13.2 Iteratees 13.3 Chapter summary 369 369 377 377 14 Going Multi-Node with Remote Actors 14.1 Many actors, many stages 14.2 Simple build tool (sbt) 14.3 Remote Airports 14.4 Going remote 14.5 Flying to the Airport 14.6 Programmatic remote deployment 14.7 Configured remote deployment 14.8 Routers across multiple nodes 14.9 Serialization 14.10 Remote system events 14.11 On the subject of lost messages 14.12 Clustering 14.13 Chapter summary 379 379 380 380 386 390 398 401 403 404 408 411 412 412 15 Sharing Data with Agents 15.1 sbt 15.2 Agents as counters 15.3 Working with agents 15.4 The API 15.5 Chapter summary 414 415 415 421 422 427 16 Granular Concurrency with Dataflow 16.1 Caveats 16.2 With that said 16.3 Getting dataflow into the build 16.4 Dataflow values 16.5 Flow 16.6 Another way to get instrument status 16.7 When to use dataflow 16.8 Chapter summary 429 429 430 430 431 431 436 437 437 17 Patterns for Akka Programming Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 438 Section 20.7 Chapter 20 · Using Akka from Java // Send it a message - getRef() is the our test actor actor.tell(new JavaMessage("Hi there"), getRef()); // Uses our JavaMessage.equals() and error messages will // use JavaMessage.toString() expectMsgEquals(duration("1 second"), new JavaMessage("Hi back")); }}; } } That’s the basic idea When you need to know more, the API reference can help you out, but you’ll find that it’s very close to what we’ve already seen; you’re just going to it from Java instead of Scala, which will make it a bit clunkier 20.7 Futures There’s nothing really surprising about the futures implementation for Java beyond what we already expect, but we’ll go over a bit of it here to give you an idea of how it works Imports You need to a fair bit of importing to get things to work out Generally, you can find what you need in akka.dispatch.*, scala.concurrent.* and java.util.concurrent.* If you can’t see what you need immediately, it’s probably in one of these key places In the examples that follow, we’re pulling in our imports as follows: // Basic Akka Imports import akka.dispatch.ExecutionContexts; import akka.dispatch.Futures; import akka.dispatch.Mapper; import akka.dispatch.Recover; import akka.dispatch.OnSuccess; import akka.dispatch.OnFailure; import akka.dispatch.OnComplete; import akka.util.Timeout; Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 501 Section 20.7 Chapter 20 · Using Akka from Java import static akka.dispatch.Futures.future; // Things we need from Scala import scala.concurrent.ExecutionContext; import scala.concurrent.Future; import scala.concurrent.Await; import scala.concurrent.duration.Duration; // Help we get from Java itself import java.util.ArrayList; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; Testing futures We’ll be driving some aspects of the Java futures through some JUnit tests, which will be set up in the following framework: public class JavaFutureSpec { // The Future needs somewhere to execute, which exists as // the ExecutionContext (we can use a Dispatcher as well, // but we're going to this a little lower down) static ExecutorService es; static ExecutionContext ec; // We're going to need a timeout later, so we'll use it from // here static Timeout timeout = new Timeout( Duration.create(2, TimeUnit.SECONDS)); // Sets up the ExecutionContext @BeforeClass public static void setup() { es = Executors.newFixedThreadPool(2); ec = ExecutionContexts.fromExecutorService(es); } // Shuts down our thread pool @AfterClass Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 502 Section 20.7 Chapter 20 · Using Akka from Java public static void teardown() { es.shutdown(); } // } Around the API Now we’ll look at how we can manipulate futures through Java to achieve the same things we’ve seen in the past with the Scala API A vanilla future Creating a simple future requires that we instantiate a callable that can execute the business logic inside the future We pass in the ExecutionContext on which the future will execute: // Use the 'future' factory method to construct the Future Future f = future(new Callable() { public String call() { return "Fibonacci"; } }, ec); assertEquals("Fibonacci", (String)Await.result(f, timeout.duration())); Using map We can use a future’s functional aspects as well, which are great for building up delayed executions without having to block any threads Doing so requires that we change from using a callable to a mapper: // Create a Future that computes a String Future f = future(new Callable() { public String call() { return "Fibonacci"; } Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 503 Section 20.7 Chapter 20 · Using Akka from Java // And then map that string into an Integer }, ec).map(new Mapper() { public Integer apply(String s) { return s.length(); } }, ec); assertEquals(new Integer(9), Await.result(f, timeout.duration())); Using flatMap As with map, we can flatMap over a future as well The indirection that we need merely creates a mapper that returns a future with a result instead of the result directly: // Ultimately we're going to get back a Future Future f = future(new Callable() { // But we start with a String public String call() { return "Fibonacci"; } // flatMap it to a Future (i.e not an Integer // as before) }, ec).flatMap(new Mapper() { public Future apply(final String s) { // Construct a new Future to an eventual Integer return future(new Callable() { public Integer call() { return s.length(); } }, ec); } }, ec); assertEquals(new Integer(9), Await.result(f, timeout.duration())); Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 504 Section 20.7 Chapter 20 · Using Akka from Java Sequencing We can also sequence a list of futures with Java as we would with Scala Let’s sum up a bunch of integers to see how you this: // Create an ArrayList of 200 Future Integers ArrayList v = new ArrayList(); for (int i = 0; i < 200; i++) { final int num = i; v.add(future(new Callable() { public Integer call() throws Exception { return new Integer(num); } }, ec)); } // Compose that list of Future Integers into a Future of a // List of Integers Future futureListOfInts = Futures.sequence(v, ec); // Map over the results and sum them up Future f = futureListOfInts.map( new Mapper() { public Long apply(Iterable ints) { long sum = 0; for (Integer i : ints) sum += i; return sum; } }, ec); assertEquals(new Long(19900), Await.result(f, timeout.duration())); Callbacks Callbacks probably have the most obvious need for implementation with classes, so the following should be fairly self-explanatory: Future f = future(new Callable() { public Integer call() { Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 505 Section 20.7 Chapter 20 · Using Akka from Java return new Integer(42); } }, ec); // Add the onSuccess callback f.onSuccess(new OnSuccess() { public void onSuccess(Integer result) { System.out.println("Awesome! I got a number: " + result); } }, ec); // Add the onFailure callback f.onFailure(new OnFailure() { public void onFailure(Throwable failure) { System.out.println("Aw, poo! It didn't work: " + failure); } }, ec); // Add the onComplete callback f.onComplete(new OnComplete() { public void onComplete(Throwable failure, Integer result) { if (failure != null) System.out.println("Aw, poo! It didn't work: " + failure); else System.out.println("Awesome! I got a number: " + result); } }, ec); Failures We can create a failure with a simple exception, as usual: Future f = future(new Callable() { // We need to declare that the main Callable method // can throw public String call() throws Exception { throw new Exception("Boo!"); } }, ec); Await.result(f, timeout.duration()); Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 506 Section 20.8 Chapter 20 · Using Akka from Java Recovering Recovering from failures is essentially the same in Java futures as it is in Scala with the now common alteration that the function be represented as an instance of a class Future f = future(new Callable() { public Integer call() throws Exception { throw new Exception( "You ain't gettin' no Integer from me."); } }, ec).recover(new Recover() { public Integer recover(Throwable t) throws Throwable { return new Integer(0); } }, ec); assertEquals(new Integer(0), Await.result(f, timeout.duration())); Using recoverWith is equivalent, but for the extra future level of indirection, as with flatMap In other words, you recover with a Recover instead of just a Recover 20.8 Manipulating agents Agents are another point of difference that’s worth describing—not because it’s a huge problem, it’s just different The bottom line here is due to the fact that Java has no support for functions as first class members of the language, which means that in order to alter the value inside an agent, you must compose the function inside of a class 20.9 Finite state machines Roll your own! Unfortunately, the FSM that ships with Akka relies heavily on Scala So heavily, in fact, that porting it to Java just isn’t possible Check the Akka reference documentation for some pointers on how to make something that’s equivalent for Java.1 Or just switch to Scala, already! Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 507 Section 20.10 Chapter 20 · Using Akka from Java 20.10 Dataflow Dataflow uses a specific feature of Scala called continuations that has no analogue in Java Sorry, folks, but if dataflow is the killer feature for you, then you’ll have to move to Scala But if you that, then you’ll probably just get dataflow as well as every other amazing thing you’ve ever wanted in life, so what the heck are you waiting for?! 20.11 Chapter summary Akka is very accessible from Java,2 so there’s no reason why you shouldn’t adopt the Akka paradigm to help you accomplish your concurrent needs whether you’re in Scala or Java Of course, Akka was written in Scala and it doesn’t confine itself unnecessarily to being 100% compatible with Java (since that would just punish us Scala guys) This means you don’t get to use all of the features that you might get in Scala, but that doesn’t mean you’re having to go without, either The Java API is very rich, and should provide you with everything you need In fact, I’m using it in my day job and it works great Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 508 Chapter 21 Now that You’re an Akka Coder Congratulations! You’ve achieved a great deal in digesting these pages You haven’t just learned the core parts of the greatest concurrency toolkit to grace the JVM to date, you’ve opened up your mind to one of the most important programming paradigms of the decade Non-blocking, fully asynchronous application design and development—which helps you create applications that are resilient in the face of failure and scales both vertically to the hardware available on your machine and horizontally across a farm of machines—is the must-have development paradigm in our multi-core world This book can’t possibly hope to make you an expert Akka programmer, and certainly not an expert in the field of this new paradigm, but you’ve climbed over that all-too-difficult hump of a learning curve that puts you in a position to learn much faster So where you go from here? 21.1 akka.io The Akka website (http://akka.io) is clearly the definitive source for information on the toolkit The reference documentation is some of the best on the web and you should head there right after you chew on this for a while The reference documentation helps you with the “what” and a decent amount of the “how,” but it’s a lot easier to understand and to put into the right context when you have a solid grasp of the “why,” which you now possess If you’re interested in some of the modules that we didn’t cover, head over there and eat them up The Scaladoc API is also a very useful resource that you should be able to sail through now, using it for the simple reference Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Section 21.2 Chapter 21 · Now that You’re an Akka Coder tool that it’s intended to be 21.2 The mailing list If you look at the Akka website, you’ll see a link for the mailing list There are a ton of helpful people on there and now is the right time to sign up; you’ve reached the point where you have a solid foundation, you know where the reference documentation is, and you can even talk the talk It’s at this point where you can start asking some good questions that people will enjoy answering I know I really like it when I see a question on the mailing list that’s actually fun to answer—a design question that presents an interesting use case or one that lets you expand the user’s knowledge to a higher level of Akka knowledge 21.3 Have fun! There’s a lot of joy in writing software that we can be proud of I don’t know about you, but when I can write a system that scales well and handles a ton of concurrent incoming events with grace and speed, while at the same time being resilient and responsive, that makes me feel like a proud papa! If you’re diligent about applying the paradigm, and grow your applications within it, and even stretch it from time to time, you’ll find that your applications are in that first-class tier of reliability and usability And if looking like the god of concurrent programming doesn’t make you feel awesome and if you don’t find the process fun, then you’ve probably made the wrong career choice But if you’ve read this book, then you’re not that person Akka is powerful, expressive, and fun Use it and be awesome Thanks for reading! Cheers! Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 510 Bibliography [Bja13] Bjarnason, Rúnar, Paul Chiusano, and Tony Morris Functional Programming in Scala Manning Publications Co., 2013 ISBN 9781617290657 [Dol12] Dolcourt, Jessica “Quad-core smartphones: This is their year.” January 2012 Available on the web at http://www.cnet.com/830117918_1-57364255-85/quad-core-smartphones-this-is-their-year/ (accessed 27 January 2013) [Fow05] Fowler, Martin “FluentInterface.” December 2005 Available on the web at http://www.martinfowler.com/bliki/FluentInterface.html (accessed 27 January 2013) [Sut05] Sutter, Herb “The Free Lunch is Over: A Fundamental Turn Toward Concurrency in Software.” March 2005 Available on the web at http://www.gotw.ca/publications/concurrencyddj.htm (accessed 27 January 2013) Original article available on the web at http://www.drdobbs.com/web-development/afundamental-turn-toward-concurrency-in/184405990 (accessed 27 January 2013) Cover · Overview · Contents · Discuss · Suggest · Glossary · Index About the author Derek Wyatt is a software architect and developer specializing in large-scale, real-time applications for the World Wide Web He’s been working with Akka since the early days of 1.0 and has used it to implement a number of applications both large and small After spending many years writing large concurrent systems in C++ using traditional concurrency mechanisms, Derek now embraces the sophisticated and beautiful simplicity of the paradigm presented in the Akka toolkit He also harbours a love of the Vim text editor and the UNIX command line that borders on the unhealthy Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Index Page numbers followed by an n refer to footnotes facilities, functions, 123 overhead, 139 scheduler, 152 system guardian, 152 user guardian, 152, 153, 185 agents, 86 blocking, 421 Akka agents, 86 components, 90 Actor, 90 ActorRef, 90 Dispatcher, 90 Mailbox, 90 dataflow, 84–85 decoupling, 91, 93 design, 124 event bus, 84 features, 32 routing, 86 scheduler, 84 test frameworks, 130 ImplicitSender, 130, 131 TestActorRef, 130 TestKit, 130, 132 toolkit, 101 tools, 29 actors, 29 callbacks/closures, 30 futures, 29 timers, 30 application, airplane Symbols ! (asynchronous message send, tell syntax) method on class Actor, 98, 118–121, 354–355 ? (ask method) on class Actor, 98, 355, 359, 360 A ActorContext trait, 121 Actor creation, 165 relationship access, 165 state, 165 system access, 165 useful functionality, 166 ActorOf method on class Actor, 109 actors behaviour, 60, 70–74, 94 compose, 81–82, 118 properties of, 92–95 side effects, 94 untyped, 70–75, 92–93 ActorSystem object, 122–124, 130, 134–138 configuration system, 152 dead letter office, 151 event stream, 152 513 Index altimeter, 101–116 crew, 155, 157–165, 169–172 ask method on class Actor, 98, 355–360 B Bjarnason, Chiusano, Morris, 55n blocking, 42–43, 91, 99–100 agents, 421 C concurrency, 32, 33, 60, 97, 98 challenges, cognitive, 25 challenges, technological, 25 delegating, 62–64 messaging, 27, 62 model of, 66 shared-state, 26 toolkit, 60 D dataflow concurrency, 84–85 dead letter office, 115, 121, 123, 151, 178, 183, 193, 355, 454, 477 decoupling, 127–128 E event bus, 84 F fluent interface, 46 “FluentInterface”(Fowler, )n46 futures accelerating raw computation, 80 compose, 81–83 knowing when everything’s done, 80 maintaining sequence, 80 promises, 99, 323, 328–330 514 G Gamma, Erich, 438 golden hammer fallacy, 104 H Heisenbugs, 27, 32, 36, 85, 430, 435 Hewitt, Carl, 29 I immutability, 44–55 data structures, 48–55 L Led Zeppelin, 362 life cycle, 65, 177–178, 187, 189, 191, 193 birth, 100 death, 65–66 M McLuhan, Marshall, 68 messages, 68–77 forwarding, 121–122 routing, 86 sending vs receiving, 75–77 typed, 68, 70–75 mock, 132, 145 modeling user, software evolution, 34–54 N non-deterministic, 98 P parallelism, 32 pattern matching Scala, 96 patterns cake, 200 error kernel, 212–216 programming reactive, 75–77, 92, 104, 369, 370, 414, 489 promises Cover · Overview · Contents · Discuss · Suggest · Glossary · Index Index complete, 329–330 dataflow values, 431, 433–436 factory method, 354 futures, 99, 323, 328–330 Props class, 101 Q “Quad-core smartphones: This is their year”(Dolcourt), 23n S sbt, 126 Scala pattern matching, 96 ScalaTest, 126n, 136 scheduler, 84 side effects, 94 Sutter, Herb, 23 T testing EventSource, 132–133 fast, 139–146 isolation, 137–139 TestProbe, 149–150 “The Free Lunch is Over: A Fundamental Turn Toward Concurrency in Software”(Sutter), 23n threads, 91 drawbacks, 40 thread pools, 40–42 typed messages, 68, 70–75 U unique id, 95, 124, 135, 240 untyped actors, 70–75, 92–93 W Winchester, Major Charles Emerson III, 94 Cover · Overview · Contents · Discuss · Suggest · Glossary · Index 515 ... toolkit 60 60 77 83 87 Why Akka? 1.1 Concurrent challenges 1.2 Akka is concurrency 1.3 Concurrency methodologies 1.4 The Akka concurrency toolkit 1.5 So, why Akka? ... Index Overview Contents List of Figures Introduction Why Akka? Concurrency and Parallelism Setting Up Akka Akka Does Concurrency Actors Akka Testing Systems, Contexts, Paths, and Locations Supervision... Granular Concurrency with Dataflow 17 Patterns for Akka Programming 18 Antipatterns for Akka Programming 19 Growing Your App with Add-On Modules 20 Using Akka from Java 21 Now that You’re an Akka