├── .gitignore ├── Example_01 ├── .idea │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── libraries │ │ ├── SBT__com_typesafe_akka_akka_actor_2_11_2_4_16_jar.xml │ │ ├── SBT__com_typesafe_config_1_3_0_jar.xml │ │ ├── SBT__org_scala_lang_modules_scala_java8_compat_2_11_0_7_0_jar.xml │ │ └── SBT__org_scala_lang_scala_library_2_11_8_jar.xml │ ├── markdown-navigator │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── modules │ │ ├── example_01-build.iml │ │ └── example_01.iml │ ├── sbt.xml │ ├── scala_compiler.xml │ └── workspace.xml ├── build.sbt ├── project │ ├── build.properties │ └── plugins.sbt └── src │ └── main │ └── scala │ └── Example_01.scala ├── Example_02 ├── .idea │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── libraries │ │ ├── SBT__com_typesafe_akka_akka_actor_2_11_2_4_16_jar.xml │ │ ├── SBT__com_typesafe_config_1_3_0_jar.xml │ │ ├── SBT__org_scala_lang_modules_scala_java8_compat_2_11_0_7_0_jar.xml │ │ └── SBT__org_scala_lang_scala_library_2_11_8_jar.xml │ ├── markdown-navigator │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── modules │ │ ├── example_02-build.iml │ │ └── example_02.iml │ ├── sbt.xml │ ├── scala_compiler.xml │ └── workspace.xml ├── build.sbt ├── project │ ├── build.properties │ └── plugins.sbt └── src │ └── main │ ├── resources │ └── application.conf │ └── scala │ └── Example_02.scala ├── Example_03 ├── .idea │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── libraries │ │ ├── SBT__com_typesafe_akka_akka_actor_2_11_2_4_16_jar.xml │ │ ├── SBT__com_typesafe_akka_akka_testkit_2_11_2_4_16_jar.xml │ │ ├── SBT__com_typesafe_config_1_3_0_jar.xml │ │ ├── SBT__org_scala_lang_modules_scala_java8_compat_2_11_0_7_0_jar.xml │ │ ├── SBT__org_scala_lang_modules_scala_parser_combinators_2_11_1_0_4_jar.xml │ │ ├── SBT__org_scala_lang_modules_scala_xml_2_11_1_0_5_jar.xml │ │ ├── SBT__org_scala_lang_scala_library_2_11_8_jar.xml │ │ ├── SBT__org_scala_lang_scala_reflect_2_11_8_jar.xml │ │ ├── SBT__org_scalactic_scalactic_2_11_3_0_0_jar.xml │ │ └── SBT__org_scalatest_scalatest_2_11_3_0_0_jar.xml │ ├── markdown-navigator │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── modules │ │ ├── example_03-build.iml │ │ └── example_03.iml │ ├── sbt.xml │ ├── scala_compiler.xml │ └── workspace.xml ├── build.sbt ├── project │ ├── build.properties │ └── plugins.sbt └── src │ ├── main │ └── scala │ │ ├── Counter.scala │ │ ├── CounterService.scala │ │ ├── FaultHandlingDocSample.scala │ │ ├── Storage.scala │ │ ├── Worker.scala │ │ └── guardian │ │ └── Guardian.scala │ └── test │ └── scala │ └── guardian │ └── GuardianSpec.scala ├── Example_04 ├── .idea │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── dictionaries │ │ └── panguansen.xml │ ├── libraries │ │ └── SBT__org_scala_lang_scala_library_2_11_8_jar.xml │ ├── markdown-navigator │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── modules │ │ ├── example_04-build.iml │ │ └── example_04.iml │ ├── sbt.xml │ ├── scala_compiler.xml │ └── workspace.xml ├── build.sbt ├── project │ ├── build.properties │ └── plugins.sbt └── src │ └── main │ ├── java │ └── futures │ │ ├── CallableTask.java │ │ └── Test.java │ └── scala │ └── futures │ ├── FutureAwait.scala │ ├── FutureFlatMap.scala │ ├── FutureForYield.scala │ ├── FutureReduce.scala │ ├── FutureSequence.scala │ ├── FutureTraverse.scala │ └── TestScalaFuture.scala ├── Example_05 ├── build.sbt ├── project │ ├── build.properties │ └── plugins.sbt └── src │ └── main │ ├── resources │ └── application.conf │ └── scala │ ├── LotteryActor.scala │ └── PersitienceQueryTest.scala ├── Example_06 ├── build.sbt ├── local │ └── src │ │ └── main │ │ ├── java │ │ ├── JoinRmiEvt.java │ │ ├── RemoteRmi.java │ │ └── RemoteRmiClient.java │ │ ├── resources │ │ └── application.conf │ │ └── scala-2.11 │ │ ├── LocalActor.scala │ │ └── LocalDemo.scala ├── project │ ├── build.properties │ └── plugins.sbt ├── remote │ ├── project │ │ └── build.properties │ └── src │ │ └── main │ │ ├── java │ │ ├── JoinRmiEvt.java │ │ ├── RemoteRMIServer.java │ │ ├── RemoteRmi.java │ │ └── RemoteRmiImpl.java │ │ ├── resources │ │ └── application.conf │ │ └── scala-2.11 │ │ ├── RemoteActor.scala │ │ └── RemoteDemo.scala └── src │ └── main │ └── scala │ └── Test.scala ├── Example_07 ├── Images.docx ├── README.txt ├── backend │ └── src │ │ └── main │ │ ├── resources │ │ └── application.conf │ │ └── scala-2.11 │ │ └── sample │ │ └── cluster │ │ └── transformation │ │ └── backend │ │ ├── TransformationBackend.scala │ │ └── TransformationBackendApp.scala ├── build.sbt ├── common │ └── src │ │ └── main │ │ └── scala-2.11 │ │ └── sample │ │ └── cluster │ │ └── transformation │ │ └── TransformationMessages.scala ├── frontend │ ├── project │ │ └── build.properties │ └── src │ │ └── main │ │ ├── resources │ │ └── application.conf │ │ └── scala-2.11 │ │ └── sample │ │ └── cluster │ │ └── transformation │ │ └── frontend │ │ ├── TransformationFrontend.scala │ │ └── TransformationFrontendApp.scala ├── project │ ├── build.properties │ └── plugins.sbt └── src │ └── main │ ├── resources │ └── application.conf │ └── scala-2.11 │ ├── ClientJobTransformationSendingActor.scala │ ├── DemoClient.scala │ └── Send.scala └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | .cache 6 | .history 7 | .lib/ 8 | dist/* 9 | target/ 10 | lib_managed/ 11 | src_managed/ 12 | project/boot/ 13 | project/plugins/project/ 14 | *.idea/ 15 | # Scala-IDE specific 16 | .scala_dependencies 17 | .worksheet 18 | -------------------------------------------------------------------------------- /Example_01/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Example_01/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_01/.idea/libraries/SBT__com_typesafe_akka_akka_actor_2_11_2_4_16_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_01/.idea/libraries/SBT__com_typesafe_config_1_3_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_01/.idea/libraries/SBT__org_scala_lang_modules_scala_java8_compat_2_11_0_7_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_01/.idea/libraries/SBT__org_scala_lang_scala_library_2_11_8_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example_01/.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_01/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Example_01/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example_01/.idea/modules/example_01-build.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Example_01/.idea/modules/example_01.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Example_01/.idea/sbt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /Example_01/.idea/scala_compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Example_01/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Example_01" 2 | 3 | version := "1.0" 4 | 5 | scalaVersion := "2.11.8" 6 | 7 | val akkaVersion = "2.4.16" 8 | 9 | libraryDependencies += 10 | "com.typesafe.akka" %% "akka-actor" % akkaVersion 11 | -------------------------------------------------------------------------------- /Example_01/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.8 -------------------------------------------------------------------------------- /Example_01/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_01/src/main/scala/Example_01.scala: -------------------------------------------------------------------------------- 1 | import akka.actor._ 2 | import akka.event.Logging 3 | 4 | /** 5 | * Created by panguansen on 17/3/19. 6 | */ 7 | trait Action { 8 | val message: String 9 | val time: Int 10 | } 11 | 12 | case class TurnOnLight(time: Int) extends Action { // 开灯消息 13 | val message = "Turn on the living room light" 14 | } 15 | 16 | case class BoilWater(time: Int) extends Action { // 烧水消息 17 | val message = "Burn a pot of water" 18 | } 19 | 20 | class RobotActor extends Actor { 21 | val log = Logging(context.system, this) 22 | def receive: Receive = { //机器人接受指令 23 | case t: TurnOnLight => log.info(s"${t.message} after ${t.time} hour") 24 | case b: BoilWater => log.info(s"${b.message} after ${b.time} hour") 25 | case _ => log.info("I can not handle this message") 26 | } 27 | } 28 | 29 | object Example_01 extends App { 30 | val actorSystem = ActorSystem("robot-system") // 31 | val robotActor = actorSystem.actorOf(Props(new RobotActor()), "robotActor") //创建一个机器人 32 | robotActor ! TurnOnLight(1) //给机器人发送一个开灯命令 33 | robotActor ! BoilWater(2) //给机器人发送一个烧水命令 34 | robotActor ! "who are you" //给机器人发送一个任意命令 35 | actorSystem terminate () 36 | } 37 | -------------------------------------------------------------------------------- /Example_02/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Example_02/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_02/.idea/libraries/SBT__com_typesafe_akka_akka_actor_2_11_2_4_16_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_02/.idea/libraries/SBT__com_typesafe_config_1_3_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_02/.idea/libraries/SBT__org_scala_lang_modules_scala_java8_compat_2_11_0_7_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_02/.idea/libraries/SBT__org_scala_lang_scala_library_2_11_8_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example_02/.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_02/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Example_02/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example_02/.idea/modules/example_02-build.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Example_02/.idea/modules/example_02.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Example_02/.idea/sbt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /Example_02/.idea/scala_compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Example_02/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Example_02" 2 | 3 | scalaVersion := "2.11.8" 4 | 5 | val akkaVersion = "2.4.16" 6 | 7 | libraryDependencies += 8 | "com.typesafe.akka" %% "akka-actor" % akkaVersion 9 | 10 | -------------------------------------------------------------------------------- /Example_02/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.8 -------------------------------------------------------------------------------- /Example_02/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_02/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | 3 | # Log level used by the configured loggers (see "loggers") as soon 4 | # as they have been started; before that, see "stdout-loglevel" 5 | # Options: OFF, ERROR, WARNING, INFO, DEBUG 6 | loglevel = "DEBUG" 7 | 8 | # Log level for the very basic logger activated during ActorSystem startup. 9 | # This logger prints the log messages to stdout (System.out). 10 | # Options: OFF, ERROR, WARNING, INFO, DEBUG 11 | stdout-loglevel = "INFO" 12 | } -------------------------------------------------------------------------------- /Example_02/src/main/scala/Example_02.scala: -------------------------------------------------------------------------------- 1 | import akka.actor._ 2 | import akka.event.Logging 3 | import akka.pattern.{ask, pipe} 4 | import akka.util.Timeout 5 | 6 | import scala.concurrent.duration._ 7 | 8 | /** 9 | * Created by panguansen on 17/3/28. 10 | */ 11 | class BossActor extends Actor { 12 | val log = Logging(context.system, this) 13 | implicit val askTimeout = Timeout(5 seconds) 14 | import context.dispatcher 15 | var taskCount = 0 16 | def receive: Receive = { 17 | case b: Business => 18 | log.info("I must to do some thing,go,go,go!") 19 | println(self.path.address) 20 | //创建Actor得到ActorRef的另一种方式,利用ActorContext.actorOf 21 | val managerActors = (1 to 3).map(i => 22 | context.actorOf(Props[ManagerActor], s"manager${i}")) //这里我们召唤3个主管 23 | //告诉他们开会商量大计划 24 | managerActors foreach { 25 | _ ? Meeting("Meeting to discuss big plans") map { 26 | case c: Confirm => 27 | //为什么这里可以知道父级Actor的信息? 28 | //熟悉树结构的同学应该知道每个节点有且只有一个父节点(根节点除外) 29 | log.info(c.actorPath.parent.toString) 30 | //根据Actor路径查找已经存在的Actor获得ActorRef 31 | //这里c.actorPath是绝对路径,你也可以根据相对路径得到相应的ActorRef 32 | val manager = context.actorSelection(c.actorPath) 33 | manager ! DoAction("Do thing") 34 | } 35 | } 36 | case d: Done => { 37 | taskCount += 1 38 | println(taskCount) 39 | if (taskCount == 3) { 40 | log.info("the project is done, we will earn much money") 41 | context.system.terminate() 42 | } 43 | } 44 | } 45 | } 46 | class ManagerActor extends Actor { 47 | val log = Logging(context.system, this) 48 | def receive: Receive = { 49 | case m: Meeting => 50 | sender() ! Confirm("I have receive command", self.path) 51 | case d: DoAction => 52 | val workerActor = context.actorOf(Props[WorkerActor], "worker") 53 | workerActor forward d 54 | } 55 | } 56 | 57 | class WorkerActor extends Actor { 58 | val log = Logging(context.system, this) 59 | def receive: Receive = { 60 | case d: DoAction => 61 | log.info("I have receive task") 62 | sender() ! Done("I hava done work") 63 | } 64 | } 65 | 66 | trait Message { 67 | val content: String 68 | } 69 | case class Business(content: String) extends Message {} 70 | case class Meeting(content: String) extends Message {} 71 | case class Confirm(content: String, actorPath: ActorPath) extends Message {} 72 | case class DoAction(content: String) extends Message {} 73 | case class Done(content: String) extends Message {} 74 | 75 | object Example_02 extends App { 76 | 77 | val actorSystem = ActorSystem("company-system") //首先我们创建一家公司 78 | //创建Actor得到ActorRef的一种方式,利用ActorSystem.actorOf 79 | val bossActor = actorSystem.actorOf(Props[BossActor], "boss") //公司有一个Boss 80 | bossActor ! Business("Fitness industry has great prospects") //从市场上观察到健身行业将会有很大的前景 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Example_03/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Example_03/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__com_typesafe_akka_akka_actor_2_11_2_4_16_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__com_typesafe_akka_akka_testkit_2_11_2_4_16_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__com_typesafe_config_1_3_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scala_lang_modules_scala_java8_compat_2_11_0_7_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scala_lang_modules_scala_parser_combinators_2_11_1_0_4_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scala_lang_modules_scala_xml_2_11_1_0_5_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scala_lang_scala_library_2_11_8_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scala_lang_scala_reflect_2_11_8_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scalactic_scalactic_2_11_3_0_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/libraries/SBT__org_scalatest_scalatest_2_11_3_0_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example_03/.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_03/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Example_03/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example_03/.idea/modules/example_03-build.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Example_03/.idea/modules/example_03.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Example_03/.idea/sbt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /Example_03/.idea/scala_compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Example_03/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Example_03" 2 | 3 | version := "1.0" 4 | 5 | scalaVersion := "2.11.8" 6 | 7 | val akkaVersion = "2.4.16" 8 | 9 | libraryDependencies ++= Seq( 10 | "com.typesafe.akka" %% "akka-actor" % akkaVersion, 11 | "com.typesafe.akka" %% "akka-testkit" % akkaVersion, 12 | "org.scalatest" %% "scalatest" % "3.0.0" 13 | ) 14 | 15 | -------------------------------------------------------------------------------- /Example_03/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.8 -------------------------------------------------------------------------------- /Example_03/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_03/src/main/scala/Counter.scala: -------------------------------------------------------------------------------- 1 | import akka.actor._ 2 | import akka.event.LoggingReceive 3 | 4 | /** 5 | * Created by panguansen on 17/3/26. 6 | */ 7 | object Counter { 8 | case class UseStorage(storage: Option[ActorRef]) 9 | } 10 | 11 | class Counter(key: String, initialValue: Long) extends Actor { 12 | import Counter._ 13 | import CounterService._ 14 | import Storage._ 15 | 16 | var count = initialValue 17 | var storage: Option[ActorRef] = None 18 | 19 | def receive = LoggingReceive { 20 | case UseStorage(s) => 21 | storage = s 22 | storeCount() 23 | 24 | case Increment(n) => 25 | count += n 26 | storeCount() 27 | 28 | case GetCurrentCount => 29 | sender() ! CurrentCount(key, count) 30 | 31 | } 32 | 33 | def storeCount() { 34 | // Delegate dangerous work, to protect our valuable state. 35 | // We can continue without storage. 36 | storage foreach { _ ! Store(Entry(key, count)) } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Example_03/src/main/scala/CounterService.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.SupervisorStrategy.Restart 2 | import akka.actor._ 3 | import akka.event.LoggingReceive 4 | 5 | import scala.concurrent.duration._ 6 | 7 | /** 8 | * Created by panguansen on 17/3/26. 9 | */ 10 | 11 | object CounterService { 12 | case class Increment(n: Int) 13 | case object GetCurrentCount 14 | case class CurrentCount(key: String, count: Long) 15 | class ServiceUnavailable(msg: String) extends RuntimeException(msg) 16 | 17 | private case object Reconnect 18 | } 19 | 20 | class CounterService extends Actor { 21 | import CounterService._ 22 | import Counter._ 23 | import Storage._ 24 | 25 | // Restart the storage child when StorageException is thrown. 26 | // After 3 restarts within 5 seconds it will be stopped. 27 | // 当storage抛出StorageException时重启storage 28 | // 如果5秒内3次重启还未成功就停止它 29 | override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 3, 30 | withinTimeRange = 5 seconds) { 31 | case _: Storage.StorageException => Restart 32 | } 33 | 34 | val key = self.path.name 35 | var storage: Option[ActorRef] = None 36 | var counter: Option[ActorRef] = None 37 | var backlog = IndexedSeq.empty[(ActorRef, Any)] 38 | val MaxBacklog = 10000 39 | 40 | import context.dispatcher // Use this Actors' Dispatcher as ExecutionContext 41 | 42 | override def preStart() { 43 | initStorage() 44 | } 45 | 46 | /** 47 | * The child storage is restarted in case of failure, but after 3 restarts, 48 | * and still failing it will be stopped. Better to back-off than continuously 49 | * failing. When it has been stopped we will schedule a Reconnect after a delay. 50 | * Watch the child so we receive Terminated message when it has been terminated. 51 | */ 52 | def initStorage() { 53 | storage = Some(context.watch(context.actorOf(Props[Storage], name = "storage"))) 54 | // Tell the counter, if any, to use the new storage 55 | counter foreach { _ ! UseStorage(storage) } 56 | // We need the initial value to be able to operate 57 | storage.get ! Get(key) 58 | } 59 | 60 | def receive = LoggingReceive { 61 | 62 | case Entry(k, v) if k == key && counter == None => 63 | // Reply from Storage of the initial value, now we can create the Counter 64 | val c = context.actorOf(Props(classOf[Counter], key, v)) 65 | counter = Some(c) 66 | // Tell the counter to use current storage 67 | c ! UseStorage(storage) 68 | // and send the buffered backlog to the counter 69 | for ((replyTo, msg) <- backlog) c.tell(msg, sender = replyTo) 70 | backlog = IndexedSeq.empty 71 | 72 | case msg @ Increment(n) => forwardOrPlaceInBacklog(msg) 73 | 74 | case msg @ GetCurrentCount => forwardOrPlaceInBacklog(msg) 75 | 76 | case Terminated(actorRef) if Some(actorRef) == storage => 77 | // After 3 restarts the storage child is stopped. 78 | // We receive Terminated because we watch the child, see initStorage. 79 | storage = None 80 | // Tell the counter that there is no storage for the moment 81 | counter foreach { _ ! UseStorage(None) } 82 | // Try to re-establish storage after while 83 | context.system.scheduler.scheduleOnce(10 seconds, self, Reconnect) 84 | 85 | case Reconnect => 86 | // Re-establish storage after the scheduled delay 87 | initStorage() 88 | } 89 | 90 | def forwardOrPlaceInBacklog(msg: Any) { 91 | // We need the initial value from storage before we can start delegate to 92 | // the counter. Before that we place the messages in a backlog, to be sent 93 | // to the counter when it is initialized. 94 | counter match { 95 | case Some(c) => c forward msg 96 | case None => 97 | if (backlog.size >= MaxBacklog) 98 | throw new ServiceUnavailable( 99 | "CounterService not available, lack of initial value") 100 | backlog :+= (sender() -> msg) 101 | } 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /Example_03/src/main/scala/FaultHandlingDocSample.scala: -------------------------------------------------------------------------------- 1 | //import akka.actor._ 2 | //import com.typesafe.config.ConfigFactory 3 | // 4 | ///** 5 | // * Created by panguansen on 17/3/26. 6 | // */ 7 | // object FaultHandlingDocSample extends App { 8 | // import Worker._ 9 | // 10 | // val config = ConfigFactory.parseString(""" 11 | // akka.loglevel = "DEBUG" 12 | // akka.actor.debug { 13 | // receive = on 14 | // lifecycle = on 15 | // } 16 | // """) 17 | // 18 | // val system = ActorSystem("FaultToleranceSample", config) 19 | // val worker = system.actorOf(Props[Worker], name = "worker") 20 | // val listener = system.actorOf(Props[Listener], name = "listener") 21 | // // start the work and listen on progress 22 | // // note that the listener is used as sender of the tell, 23 | // // i.e. it will receive replies from the worker 24 | // worker.tell(Start, sender = listener) 25 | // } 26 | // 27 | -------------------------------------------------------------------------------- /Example_03/src/main/scala/Storage.scala: -------------------------------------------------------------------------------- 1 | import akka.actor._ 2 | import akka.event.LoggingReceive 3 | 4 | /** 5 | * Created by panguansen on 17/3/26. 6 | */ 7 | object Storage { 8 | case class Store(entry: Entry) 9 | case class Get(key: String) 10 | case class Entry(key: String, value: Long) 11 | class StorageException(msg: String) extends RuntimeException(msg) 12 | } 13 | 14 | class Storage extends Actor { 15 | import Storage._ 16 | 17 | val db = DummyDB 18 | 19 | def receive = LoggingReceive { 20 | case Store(Entry(key, count)) => db.save(key, count) 21 | case Get(key) => sender() ! Entry(key, db.load(key).getOrElse(0L)) 22 | } 23 | } 24 | 25 | object DummyDB { 26 | import Storage.StorageException 27 | private var db = Map[String, Long]() 28 | 29 | @throws(classOf[StorageException]) 30 | def save(key: String, value: Long): Unit = synchronized { 31 | if (11 <= value && value <= 14) 32 | throw new StorageException("Simulated store failure " + value) 33 | db += (key -> value) 34 | } 35 | 36 | @throws(classOf[StorageException]) 37 | def load(key: String): Option[Long] = synchronized { 38 | db.get(key) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Example_03/src/main/scala/Worker.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.SupervisorStrategy.Stop 2 | import akka.actor._ 3 | import akka.event.LoggingReceive 4 | import akka.util.Timeout 5 | import akka.pattern.{ ask, pipe } 6 | 7 | import scala.concurrent.duration._ 8 | /** 9 | * Created by panguansen on 17/3/26. 10 | */ 11 | object Worker { 12 | case object Start 13 | case object Do 14 | case class Progress(percent: Double) 15 | } 16 | 17 | 18 | class Listener extends Actor with ActorLogging { 19 | import Worker._ 20 | // If we don't get any progress within 15 seconds then the service is unavailable 21 | //假如我们在15秒之内得不到任何反馈即表示当前服务不可用 22 | context.setReceiveTimeout(15 seconds) 23 | 24 | def receive = { 25 | case Progress(percent) => 26 | //记录当前进度 27 | log.info("Current progress: {} %", percent) 28 | if (percent >= 20.0) { 29 | log.info("That's all, shutting down") 30 | context.system.terminate() 31 | } 32 | 33 | case ReceiveTimeout => 34 | //15秒之内没有任务反馈,服务不可用,终止程序 35 | log.error("Shutting down due to unavailable service") 36 | context.system.terminate() 37 | } 38 | } 39 | 40 | class Worker extends Actor with ActorLogging { 41 | import Worker._ 42 | import CounterService._ 43 | implicit val askTimeout = Timeout(5 seconds) 44 | 45 | // Stop the CounterService child if it throws ServiceUnavailable 46 | // 假如接收到抛出的异常信息为服务不可用,停止CounterService的子Actor 47 | override val supervisorStrategy = OneForOneStrategy() { 48 | case _: CounterService.ServiceUnavailable => Stop 49 | } 50 | 51 | // The sender of the initial Start message will continuously be notified 52 | // about progress 53 | var progressListener: Option[ActorRef] = None 54 | val counterService = context.actorOf(Props[CounterService], name = "counter") 55 | val totalCount = 51 56 | import context.dispatcher // Use this Actors' Dispatcher as ExecutionContext 57 | 58 | def receive = LoggingReceive { 59 | case Start if progressListener.isEmpty => 60 | progressListener = Some(sender) 61 | context.system.scheduler.schedule(Duration.Zero, 1 second, self, Do) 62 | 63 | case Do => 64 | counterService ! Increment(1) 65 | counterService ! Increment(1) 66 | counterService ! Increment(1) 67 | 68 | // 这里可以看成 progressListener.get !current progress 69 | // Actor异步获取结果,并根据结果的状态给发送者回应不同的消息 70 | counterService ? GetCurrentCount map { 71 | case CurrentCount(_, count) => Progress(100.0 * count / totalCount) 72 | } pipeTo progressListener.get 73 | } 74 | } -------------------------------------------------------------------------------- /Example_03/src/main/scala/guardian/Guardian.scala: -------------------------------------------------------------------------------- 1 | package guardian 2 | 3 | import akka.actor._ 4 | import akka.actor.OneForOneStrategy 5 | import akka.actor.SupervisorStrategy._ 6 | import akka.event.Logging 7 | 8 | import scala.concurrent.duration._ 9 | 10 | /** 11 | * Created by panguansen on 17/3/26. 12 | */ 13 | class Supervisor extends Actor { 14 | 15 | //监管下属,根据下属抛出的异常进行相应的处理 16 | override val supervisorStrategy = 17 | OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { 18 | case _: ArithmeticException => Resume 19 | case _: NullPointerException => Restart 20 | case _: IllegalArgumentException => Stop 21 | case _: Exception => Escalate 22 | } 23 | var childIndex = 0 //用于标示下属Actor的序号 24 | 25 | def receive = { 26 | case p: Props => 27 | childIndex += 1 28 | //返回一个Child Actor的引用,所以Supervisor Actor是Child Actor的监管者 29 | sender() ! context.actorOf(p,s"child${childIndex}") 30 | } 31 | 32 | // override default to kill all children during restart 33 | // override def preRestart(cause: Throwable, msg: Option[Any]) {} 34 | } 35 | 36 | class Child extends Actor { 37 | val log = Logging(context.system, this) 38 | var state = 0 39 | def receive = { 40 | case ex: Exception => throw ex //抛出相应的异常 41 | case x: Int => state = x //改变自身状态 42 | case s: Command if s.content == "get" => 43 | log.info(s"the ${s.self} state is ${state}") 44 | sender() ! state //返回自身状态 45 | } 46 | } 47 | 48 | case class Command( //相应命令 49 | content: String, 50 | self: String 51 | ) 52 | -------------------------------------------------------------------------------- /Example_03/src/test/scala/guardian/GuardianSpec.scala: -------------------------------------------------------------------------------- 1 | package guardian 2 | 3 | import akka.actor.{ActorRef, ActorSystem, InternalActorRef, Props, Terminated} 4 | import akka.testkit.{ImplicitSender, TestKit} 5 | import org.scalatest.{Matchers, WordSpecLike} 6 | 7 | /** 8 | * Created by panguansen on 17/4/7. 9 | */ 10 | class GuardianSpec(_system: ActorSystem) 11 | extends TestKit(_system) 12 | with WordSpecLike 13 | with Matchers 14 | with ImplicitSender { 15 | 16 | def this() = this(ActorSystem("GuardianSpec")) 17 | 18 | "A supervisor" must { 19 | 20 | "apply the chosen strategy for its child" in { 21 | // code here 22 | val supervisor = system.actorOf(Props[Supervisor], "supervisor") 23 | 24 | supervisor ! Props[Child] 25 | val child = expectMsgType[ActorRef] // 从 TestKit 的 testActor 中获取回应 26 | 27 | //TestOne 28 | child ! 42 // 将状态设为 42 29 | child ! Command("get",child.path.name) 30 | expectMsg(42) 31 | 32 | //TestTwo 33 | child ! new ArithmeticException // crash it 34 | child ! Command("get",child.path.name) 35 | expectMsg(42) 36 | 37 | //TestThree 38 | child ! new NullPointerException // crash it harder 39 | child ! "get" 40 | expectMsg(0) 41 | 42 | 43 | //TestFour 44 | supervisor ! Props[Child] // create new child 45 | val child2 = expectMsgType[ActorRef] 46 | child2 ! 100 // 将状态设为 100 47 | watch(child) // have testActor watch “child” 48 | child ! new IllegalArgumentException // break it 49 | expectMsgPF() { 50 | case Terminated(`child`) => (println("the child stop")) 51 | } 52 | child2 ! Command("get",child2.path.name) 53 | expectMsg(100) 54 | 55 | 56 | //TestFive 57 | watch(child2) 58 | child2 ! Command("get",child2.path.name) // verify it is alive 59 | expectMsg(100) 60 | supervisor ! Props[Child] // create new child 61 | val child3 = expectMsgType[ActorRef] 62 | child2 ! new Exception("CRASH") // escalate failure 63 | // expectMsgPF() { 64 | // case t @ Terminated(`child2`) if t.existenceConfirmed => ( 65 | // println("the child2 stop") 66 | // ) 67 | // } 68 | child3 ! Command("get",child.path.name) 69 | expectMsg(0) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Example_04/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Example_04/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_04/.idea/dictionaries/panguansen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_04/.idea/libraries/SBT__org_scala_lang_scala_library_2_11_8_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example_04/.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Example_04/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 35 | 36 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Android 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Example_04/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example_04/.idea/modules/example_04-build.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Example_04/.idea/modules/example_04.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example_04/.idea/sbt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /Example_04/.idea/scala_compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Example_04/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Example_04" 2 | 3 | version := "1.0" 4 | 5 | scalaVersion := "2.11.8" 6 | 7 | //libraryDependencies += "junit" %% "junit" % "4.12" 8 | libraryDependencies += "org.scala-lang.modules" %% "scala-async" % "0.9.6" 9 | -------------------------------------------------------------------------------- /Example_04/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.8 -------------------------------------------------------------------------------- /Example_04/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_04/src/main/java/futures/CallableTask.java: -------------------------------------------------------------------------------- 1 | package futures; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | /** 6 | * Created by panguansen on 17/5/14. 7 | */ 8 | public class CallableTask implements Callable{ 9 | @Override 10 | public Object call() throws Exception { 11 | System.out.println("lalala"); 12 | Thread.sleep(1000); 13 | throw new Exception("error"); 14 | // return "hello world"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example_04/src/main/java/futures/Test.java: -------------------------------------------------------------------------------- 1 | package futures; 2 | 3 | import java.util.concurrent.*; 4 | 5 | /** 6 | * Created by panguansen on 17/5/14. 7 | */ 8 | public class Test { 9 | public static void main(String[] args) { 10 | ExecutorService es = Executors.newSingleThreadExecutor(); 11 | Future f = es.submit(() -> { 12 | System.out.println("execute call"); 13 | Thread.sleep(1000); 14 | return 5; 15 | }); 16 | try { 17 | System.out.println(f.isDone()); 18 | System.out.println(f.get(2000, TimeUnit.MILLISECONDS)); 19 | System.out.println(f.isDone()); 20 | } catch (InterruptedException e) { 21 | e.printStackTrace(); 22 | } catch (ExecutionException e) { 23 | e.printStackTrace(); 24 | } catch (TimeoutException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/FutureAwait.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent._ 4 | import ExecutionContext.Implicits.global 5 | import scala.async.Async.{async, await} 6 | /** 7 | * Created by panguansen on 17/6/27. 8 | */ 9 | object FutureAwait extends App { 10 | val fut1 = Future { 11 | println("enter task1") 12 | Thread.sleep(2000) 13 | 1 + 1 14 | } 15 | 16 | val fut2 = Future { 17 | println("enter task2") 18 | Thread.sleep(1000) 19 | 2 + 2 20 | } 21 | 22 | val v1 = async { 23 | await(fut1) + await(fut2) 24 | } 25 | 26 | v1 foreach { 27 | case r => println(s"the result1 is ${v1}") 28 | } 29 | 30 | //顺序执行 31 | Thread.sleep(2500) 32 | val v2 = async { 33 | await(Future { 34 | println("enter task1") 35 | Thread.sleep(2000) 36 | 1 + 1 37 | }) + await(Future { 38 | println("enter task2") 39 | Thread.sleep(1000) 40 | 2 + 2 41 | }) 42 | } 43 | println(s"the result2 is ${v2}") 44 | Thread.sleep(3500) 45 | } 46 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/FutureFlatMap.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by panguansen on 17/5/17. 8 | */ 9 | object FutureFlatMap extends App{ 10 | 11 | val fut1 = Future { 12 | println("enter task1") 13 | Thread.sleep(2000) 14 | 1 + 1 15 | } 16 | 17 | val fut2 = Future { 18 | println("enter task2") 19 | Thread.sleep(1000) 20 | 2 + 2 21 | } 22 | 23 | fut1.flatMap { v1 => 24 | fut2.map { v2 => 25 | println(s"the result is ${v1 + v2}") 26 | } 27 | } 28 | Thread.sleep(2500) 29 | } 30 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/FutureForYield.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by panguansen on 17/5/17. 8 | */ 9 | object FutureForYield extends App{ 10 | 11 | val fut1 = Future { 12 | println("enter task1") 13 | Thread.sleep(2000) 14 | 1 + 1 15 | } 16 | 17 | val fut2 = Future { 18 | println("enter task2") 19 | Thread.sleep(1000) 20 | 2 + 2 21 | } 22 | 23 | //异步执行 24 | for { 25 | v1 <- fut1 26 | v2 <- fut2 27 | } yield println(s"the result is ${v1 + v2}") 28 | 29 | //顺序执行 30 | Thread.sleep(2500) 31 | for { 32 | v1 <- Future { 33 | println("enter task1") 34 | Thread.sleep(2000) 35 | 1 + 1 36 | } 37 | v2 <- Future { 38 | println("enter task2") 39 | Thread.sleep(1000) 40 | 2 + 2 41 | } 42 | } yield println(s"the result is ${v1 + v2}") 43 | Thread.sleep(3500) 44 | } 45 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/FutureReduce.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by panguansen on 17/5/17. 8 | */ 9 | object FutureReduce extends App { 10 | 11 | // 理想情况: 列表中的Future全部都成功 12 | val squares: Seq[Future[Int]] = for (i <- 0 until 10) yield Future { i * i } 13 | // reduce: 完成 Seq[Future[Int]] => Future[Int] 的转换 14 | val sumOfSquares: Future[Int] = Future.reduce(squares)(_ + _) 15 | 16 | sumOfSquares foreach { 17 | case sum => println(s"Sum of squares = $sum") 18 | } 19 | 20 | val futureWithException = List(Future( 1 + 2), Future(throw new RuntimeException("hello"))) 21 | val reduceFutures = Future.reduce(futureWithException)(_ + _) 22 | 23 | // 不会被执行 24 | reduceFutures foreach { num => // 只处理成功的情况 25 | println(s"plus with exception = $num") 26 | } 27 | 28 | // 被调用执行,其结果是列表中第一个最新计算完成的异常的Future 29 | reduceFutures.failed foreach { e => // 只处理失败的情况 30 | println(s"plus with exception = $e") 31 | } 32 | 33 | Thread.sleep(2000) 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/FutureSequence.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by panguansen on 17/5/17. 8 | */ 9 | object FutureSequence extends App { 10 | 11 | // 理想情况: 列表中的Future全部都成功 12 | val listF: Seq[Future[Int]] = for (i <- 0 until 10) yield Future { i * i } 13 | // sequence: 完成 Seq[Future[Int]] => Future[Seq[Int]] 的转换 14 | val fList: Future[Seq[Int]] = Future.sequence(listF) 15 | 16 | for { 17 | r <- fList 18 | } yield println(r) 19 | 20 | Thread.sleep(1000) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/FutureTraverse.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by panguansen on 17/5/17. 8 | */ 9 | object FutureTraverse extends App { 10 | 11 | val list = List(1, 2, 3, 4, 5) 12 | 13 | // 这种方式会使用list的size个工作线程,这里是使用了5个线程 14 | val listFutures: List[Future[Int]] = list map (num => Future(num * num)) 15 | listFutures.foreach { case future => 16 | future foreach { 17 | num => println(s"num in future is $num") 18 | } 19 | } 20 | 21 | // 这种方式只会使用一个工作线程 22 | val futureList: Future[List[Int]] = Future.traverse(list)(num => Future(num * num)) 23 | futureList.foreach{ case listNum => 24 | listNum foreach { 25 | num => println(s"num in list is $num") 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Example_04/src/main/scala/futures/TestScalaFuture.scala: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import scala.concurrent.Future 4 | import scala.util.Success 5 | import scala.concurrent.ExecutionContext.Implicits.global 6 | 7 | /** 8 | * Created by panguansen on 17/5/17. 9 | */ 10 | object TestScalaFuture extends App { 11 | 12 | val fut = Future { 13 | Thread.sleep(1000) 14 | 1 + 1 15 | } 16 | 17 | fut onComplete { 18 | case Success(r) => println(s"the result is ${r}") 19 | case _ => println("some Exception") 20 | } 21 | // fut onComplete { 22 | // case Success(r) => println(r+2) 23 | // case _ => println("some Exception") 24 | // } 25 | 26 | println("I am working") 27 | Thread.sleep(2000) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Example_05/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Example_05" 2 | 3 | version := "1.0" 4 | 5 | scalaVersion := "2.11.8" 6 | 7 | libraryDependencies ++= Seq( 8 | "com.typesafe.akka" %% "akka-actor" % "2.4.16", 9 | "com.typesafe.akka" %% "akka-persistence" % "2.4.16", 10 | "org.iq80.leveldb" % "leveldb" % "0.7", 11 | "org.fusesource.leveldbjni" % "leveldbjni-all" % "1.8", 12 | "com.twitter" %% "chill-akka" % "0.8.0", 13 | "com.typesafe.akka" %% "akka-persistence-query" % "2.5.3" 14 | ) 15 | -------------------------------------------------------------------------------- /Example_05/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.15 -------------------------------------------------------------------------------- /Example_05/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_05/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka.persistence.journal.plugin = "akka.persistence.journal.leveldb" 2 | akka.persistence.snapshot-store.plugin = "akka.persistence.snapshot-store.local" 3 | 4 | akka.persistence.journal.leveldb.dir = "log/journal" 5 | akka.persistence.snapshot-store.local.dir = "log/snapshots" 6 | 7 | # DO NOT USE THIS IN PRODUCTION !!! 8 | # See also https://github.com/typesafehub/activator/issues/287 9 | akka.persistence.journal.leveldb.native = false 10 | 11 | # Configuration for the LeveldbReadJournal 12 | akka.persistence.query.journal.leveldb { 13 | # Implementation class of the LevelDB ReadJournalProvider 14 | class = "akka.persistence.query.journal.leveldb.LeveldbReadJournalProvider" 15 | 16 | # Absolute path to the write journal plugin configuration entry that this 17 | # query journal will connect to. That must be a LeveldbJournal or SharedLeveldbJournal. 18 | # If undefined (or "") it will connect to the default journal as specified by the 19 | # akka.persistence.journal.plugin property. 20 | write-plugin = "" 21 | 22 | # The LevelDB write journal is notifying the query side as soon as things 23 | # are persisted, but for efficiency reasons the query side retrieves the events 24 | # in batches that sometimes can be delayed up to the configured `refresh-interval`. 25 | refresh-interval = 3s 26 | 27 | # How many events to fetch in one query (replay) and keep buffered until they 28 | # are delivered downstreams. 29 | max-buffer-size = 100 30 | } 31 | //akka { 32 | // loggers = ["akka.event.slf4j.Slf4jLogger"] 33 | // loglevel = "DEBUG" 34 | // logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" 35 | //} 36 | 37 | //akka { 38 | // persistence { 39 | // journal.plugin = "akka-persistence-sql-async.journal" 40 | // snapshot-store.plugin = "akka-persistence-sql-async.snapshot-store" 41 | // } 42 | //} 43 | // 44 | //akka-persistence-sql-async { 45 | // journal.class = "akka.persistence.journal.sqlasync.MySQLAsyncWriteJournal" 46 | // snapshot-store.class = "akka.persistence.snapshot.sqlasync.MySQLSnapshotStore" 47 | // 48 | // # For PostgreSQL 49 | // # journal.class = "akka.persistence.journal.sqlasync.PostgreSQLAsyncWriteJournal" 50 | // # snapshot-store.class = "akka.persistence.snapshot.sqlasync.PostgreSQLSnapshotStore" 51 | // 52 | // user = "root" 53 | // password = "" 54 | // url = "jdbc:mysql://localhost:3306/akka_persistence_sql_async" 55 | // max-pool-size = 4 56 | // wait-queue-capacity = 10000 57 | // 58 | // metadata-table-name = "persistence_metadata" 59 | // journal-table-name = "persistence_journal" 60 | // snapshot-table-name = "persistence_snapshot" 61 | //} 62 | 63 | akka.actor.serializers { 64 | kryo = "com.twitter.chill.akka.AkkaSerializer" 65 | } 66 | akka.actor.serialization-bindings { 67 | "scala.Product" = kryo 68 | "akka.persistence.PersistentRepr" = kryo 69 | } 70 | -------------------------------------------------------------------------------- /Example_05/src/main/scala/LotteryActor.scala: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.{ExecutorService, Executors} 2 | 3 | import akka.actor.Actor.Receive 4 | import akka.actor.{ActorLogging, ActorRef, ActorSystem, Props} 5 | import akka.persistence._ 6 | import akka.pattern.ask 7 | import akka.util.Timeout 8 | 9 | import scala.collection.mutable.ArrayBuffer 10 | import scala.concurrent.duration._ 11 | import scala.concurrent.ExecutionContext.Implicits.global 12 | 13 | /** 14 | * Created by panguansen on 17/7/19. 15 | */ 16 | case class LotteryCmd( 17 | userId: Long, 18 | username: String, 19 | email: String 20 | ) 21 | case class LuckyEvent( //抽奖成功事件 22 | userId: Long, 23 | luckyMoney: Int 24 | ) 25 | case class FailureEvent( //抽奖失败事件 26 | userId: Long, 27 | reason: String 28 | ) 29 | case class Lottery( 30 | totalAmount: Int, //红包总金额 31 | remainAmount: Int //剩余红包金额 32 | ) { 33 | def update(luckyMoney: Int) = { 34 | copy( 35 | remainAmount = remainAmount - luckyMoney 36 | ) 37 | } 38 | } 39 | class LotteryActor(initState: Lottery) extends PersistentActor with ActorLogging{ 40 | override def persistenceId: String = "lottery-actor-1" 41 | 42 | var state = initState //初始化Actor的状态 43 | 44 | override def receiveRecover: Receive = { 45 | case event: LuckyEvent => 46 | updateState(event) //恢复Actor时根据持久化的事件恢复Actor状态 47 | case SnapshotOffer(_, snapshot: Lottery) => 48 | log.info(s"Recover actor state from snapshot and the snapshot is ${snapshot}") 49 | state = snapshot //利用快照恢复Actor的状态 50 | case RecoveryCompleted => log.info("the actor recover completed") 51 | } 52 | 53 | def updateState(le: LuckyEvent) = 54 | state = state.update(le.luckyMoney) //更新自身状态 55 | 56 | override def receiveCommand: Receive = { 57 | case lc: LotteryCmd => 58 | doLottery(lc) match { //进行抽奖,并得到抽奖结果,根据结果做出不同的处理 59 | case le: LuckyEvent => //抽到随机红包 60 | persist(le) { event => 61 | updateState(event) 62 | increaseEvtCountAndSnapshot() 63 | sender() ! event 64 | } 65 | case fe: FailureEvent => //红包已经抽完 66 | sender() ! fe 67 | } 68 | case "saveSnapshot" => // 接收存储快照命令执行存储快照操作 69 | saveSnapshot(state) 70 | case SaveSnapshotSuccess(metadata) => ??? //你可以在快照存储成功后做一些操作,比如删除之前的快照等 71 | } 72 | 73 | 74 | private def increaseEvtCountAndSnapshot() = { 75 | val snapShotInterval = 5 76 | if (lastSequenceNr % snapShotInterval == 0 && lastSequenceNr != 0) { //当有持久化5个事件后我们便存储一次当前Actor状态的快照 77 | self ! "saveSnapshot" 78 | } 79 | } 80 | 81 | 82 | def doLottery(lc: LotteryCmd) = { //抽奖逻辑具体实现 83 | if (state.remainAmount > 0) { 84 | val luckyMoney = scala.util.Random.nextInt(state.remainAmount) + 1 85 | LuckyEvent(lc.userId, luckyMoney) 86 | } 87 | else { 88 | FailureEvent(lc.userId, "下次早点来,红包已被抽完咯!") 89 | } 90 | } 91 | } 92 | 93 | 94 | class LotteryActorN(initState: Lottery) extends PersistentActor with ActorLogging{ 95 | override def persistenceId: String = "lottery-actor-2" 96 | 97 | var state = initState //初始化Actor的状态 98 | 99 | override def receiveRecover: Receive = { 100 | case event: LuckyEvent => 101 | updateState(event) //恢复Actor时根据持久化的事件恢复Actor状态 102 | case SnapshotOffer(_, snapshot: Lottery) => 103 | log.info(s"Recover actor state from snapshot and the snapshot is ${snapshot}") 104 | state = snapshot //利用快照恢复Actor的状态 105 | case RecoveryCompleted => log.info("the actor recover completed") 106 | } 107 | 108 | def updateState(le: LuckyEvent) = 109 | state = state.update(le.luckyMoney) //更新自身状态 110 | 111 | var lotteryQueue : ArrayBuffer[(LotteryCmd, ActorRef)] = ArrayBuffer() 112 | 113 | context.system.scheduler //定时器,定时触发抽奖逻辑 114 | .schedule( 115 | 0.milliseconds, 116 | 100.milliseconds, 117 | new Runnable { 118 | def run = { 119 | self ! "doLottery" 120 | } 121 | } 122 | ) 123 | 124 | override def receiveCommand: Receive = { 125 | case lc: LotteryCmd => 126 | lotteryQueue = lotteryQueue :+ (lc, sender()) //参与信息加入抽奖队列 127 | println(s"the lotteryQueue size is ${lotteryQueue.size}") 128 | if (lotteryQueue.size > 5) //当参与人数有5个时触发抽奖 129 | joinN(lotteryQueue) 130 | case "doLottery" => 131 | if (lotteryQueue.size > 0) 132 | joinN(lotteryQueue) 133 | case "saveSnapshot" => // 接收存储快照命令执行存储快照操作 134 | saveSnapshot(state) 135 | case SaveSnapshotSuccess(metadata) => ??? //你可以在快照存储成功后做一些操作,比如删除之前的快照等 136 | } 137 | 138 | private def joinN(lotteryQueue: ArrayBuffer[(LotteryCmd, ActorRef)]) = { //批量处理抽奖结果 139 | val rs = doLotteryN(lotteryQueue) 140 | val success = rs.collect { //得到其中中奖的相应信息 141 | case (event: LuckyEvent, ref: ActorRef) => 142 | event -> ref 143 | }.toMap 144 | println(success) 145 | val failure = rs.collect { //得到其中未中奖的相应信息 146 | case (event: FailureEvent, ref: ActorRef) => event -> ref 147 | } 148 | persistAll(success.keys.toIndexedSeq) { //批量持久化中奖用户事件 149 | case event => println(event) 150 | updateState(event) 151 | increaseEvtCountAndSnapshot() 152 | success(event) ! event 153 | } 154 | failure.foreach { 155 | case (event, ref) => ref ! event 156 | } 157 | this.lotteryQueue.clear() //清空参与队列 158 | } 159 | 160 | 161 | private def increaseEvtCountAndSnapshot() = { 162 | val snapShotInterval = 5 163 | if (lastSequenceNr % snapShotInterval == 0 && lastSequenceNr != 0) { //当有持久化5个事件后我们便存储一次当前Actor状态的快照 164 | self ! "saveSnapshot" 165 | } 166 | } 167 | 168 | private def doLotteryN(lotteryQueue: ArrayBuffer[(LotteryCmd, ActorRef)]) = { //抽奖逻辑具体实现 169 | var remainAmount = state.remainAmount 170 | lotteryQueue.map(lq => 171 | if (remainAmount > 0) { 172 | val luckyMoney = scala.util.Random.nextInt(remainAmount) + 1 173 | remainAmount = remainAmount - luckyMoney 174 | (LuckyEvent(lq._1.userId, luckyMoney),lq._2) 175 | } 176 | else { 177 | (FailureEvent(lq._1.userId, "下次早点来,红包已被抽完咯!"),lq._2) 178 | } 179 | ) 180 | } 181 | } 182 | 183 | 184 | object PersistenceTest extends App { 185 | val lottery = Lottery(10000,10000) 186 | val system = ActorSystem("example-05") 187 | // val lotteryActor = system.actorOf(Props(new LotteryActor(lottery)), "LotteryActor-1") //创建抽奖Actor 188 | val lotteryActor = system.actorOf(Props(new LotteryActorN(lottery)), "LotteryActor-2") //创建抽奖Actor 189 | val pool: ExecutorService = Executors.newFixedThreadPool(10) 190 | val r = (1 to 100).map(i => 191 | new LotteryRun(lotteryActor, LotteryCmd(i.toLong,"godpan","xx@gmail.com")) //创建100个抽奖请求 192 | ) 193 | r.map(pool.execute(_)) //使用线程池来发起抽奖请求,模拟同时多人参加 194 | Thread.sleep(5000) 195 | pool.shutdown() 196 | system.terminate() 197 | } 198 | 199 | class LotteryRun(lotteryActor: ActorRef, lotteryCmd: LotteryCmd) extends Runnable { //抽奖请求 200 | implicit val timeout = Timeout(3.seconds) 201 | def run: Unit = { 202 | for { 203 | fut <- lotteryActor ? lotteryCmd 204 | } yield fut match { //根据不同事件显示不同的抽奖结果 205 | case le: LuckyEvent => println(s"恭喜用户${le.userId}抽到了${le.luckyMoney}元红包") 206 | case fe: FailureEvent => println(fe.reason) 207 | case _ => println("系统错误,请重新抽取") 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /Example_05/src/main/scala/PersitienceQueryTest.scala: -------------------------------------------------------------------------------- 1 | import akka.NotUsed 2 | import akka.actor.ActorSystem 3 | import akka.persistence.query.{EventEnvelope, PersistenceQuery} 4 | import akka.persistence.query.journal.leveldb.scaladsl.LeveldbReadJournal 5 | import akka.stream.ActorMaterializer 6 | import akka.stream.scaladsl.Source 7 | /** 8 | * Created by panguansen on 17/7/23. 9 | */ 10 | object PersistenceQueryTest extends App { 11 | val system = ActorSystem("example-05") 12 | implicit val mat = ActorMaterializer()(system) 13 | val queries = PersistenceQuery(system).readJournalFor[LeveldbReadJournal]( 14 | LeveldbReadJournal.Identifier) 15 | 16 | val src: Source[EventEnvelope, NotUsed] = 17 | queries.eventsByPersistenceId("lottery-actor-2", 0L, Long.MaxValue) 18 | 19 | src.runForeach { event => println("Event: " + event) } 20 | Thread.sleep(3000) 21 | system.terminate() 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Example_06/build.sbt: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import sbt.Keys._ 3 | 4 | lazy val AllLibraryDependencies = 5 | Seq( 6 | "com.typesafe.akka" %% "akka-actor" % "2.5.3", 7 | "com.typesafe.akka" %% "akka-remote" % "2.5.3", 8 | "com.twitter" %% "chill-akka" % "0.8.4" 9 | ) 10 | 11 | lazy val commonSettings = Seq( 12 | name := "AkkaRemoting", 13 | version := "1.0", 14 | scalaVersion := "2.11.11", 15 | libraryDependencies := AllLibraryDependencies 16 | ) 17 | 18 | lazy val remote = (project in file("remote")) 19 | .settings(commonSettings: _*) 20 | .settings( 21 | // other settings 22 | ) 23 | 24 | lazy val local = (project in file("local")) 25 | .settings(commonSettings: _*) 26 | .settings( 27 | // other settings 28 | ) 29 | -------------------------------------------------------------------------------- /Example_06/local/src/main/java/JoinRmiEvt.java: -------------------------------------------------------------------------------- 1 | import java.io.Serializable; 2 | import java.rmi.Remote; 3 | 4 | /** 5 | * Created by panguansen on 17/8/24. 6 | */ 7 | public class JoinRmiEvt implements Remote , Serializable{ 8 | private static final long serialVersionUID = 1L; 9 | private Long id; 10 | private String name; 11 | 12 | public JoinRmiEvt(Long id, String name) { 13 | this.id = id; 14 | this.name = name; 15 | } 16 | 17 | public Long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Example_06/local/src/main/java/RemoteRmi.java: -------------------------------------------------------------------------------- 1 | import java.rmi.Remote; 2 | import java.rmi.RemoteException; 3 | 4 | /** 5 | * Created by panguansen on 17/8/24. 6 | */ 7 | public interface RemoteRmi extends Remote { 8 | public void sendNoReturn(String message) throws RemoteException, InterruptedException; 9 | public String sendHasReturn(JoinRmiEvt joinRmiEvt) throws RemoteException; 10 | } 11 | -------------------------------------------------------------------------------- /Example_06/local/src/main/java/RemoteRmiClient.java: -------------------------------------------------------------------------------- 1 | import java.net.MalformedURLException; 2 | import java.rmi.Naming; 3 | import java.rmi.NotBoundException; 4 | import java.rmi.RemoteException; 5 | 6 | /** 7 | * Created by panguansen on 17/8/24. 8 | */ 9 | public class RemoteRmiClient { 10 | public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException, InterruptedException { 11 | System.out.println("the client has started"); 12 | String url = "rmi://127.0.0.1:2553/remote_rmi"; 13 | RemoteRmi remoteRmi = (RemoteRmi) Naming.lookup(url); 14 | Long startTime = System.currentTimeMillis(); 15 | System.out.println("the client has running"); 16 | remoteRmi.sendNoReturn("send no return"); 17 | System.out.println(remoteRmi.sendHasReturn(new JoinRmiEvt(1L,"godpan"))); 18 | Long endTime = System.currentTimeMillis(); 19 | System.out.println("the running time is " + (endTime - startTime)); 20 | System.out.println("the client has end"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example_06/local/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | actor { 3 | provider = "akka.remote.RemoteActorRefProvider" 4 | serializers { 5 | kryo = "com.twitter.chill.akka.AkkaSerializer" 6 | } 7 | serialization-bindings { 8 | // "java.io.Serializable" = none 9 | "scala.Product" = kryo 10 | } 11 | } 12 | remote { 13 | enabled-transports = ["akka.remote.netty.tcp"] 14 | netty.tcp { 15 | hostname = "127.0.0.1" 16 | port = 0 17 | } 18 | } 19 | } 20 | 21 | remote { 22 | actor { 23 | name { 24 | test = "akka.tcp://RemoteDemoSystem@127.0.0.1:4444/user/RemoteActor" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Example_06/local/src/main/scala-2.11/LocalActor.scala: -------------------------------------------------------------------------------- 1 | import akka.actor._ 2 | import akka.actor.Actor.Receive 3 | import akka.pattern.ask 4 | import akka.util.Timeout 5 | import com.typesafe.config.ConfigFactory 6 | import scala.concurrent.duration._ 7 | import scala.concurrent.ExecutionContext.Implicits.global 8 | 9 | /** 10 | * Created by panguansen on 17/8/14. 11 | */ 12 | case object Init 13 | case object SendNoReturn 14 | case object SendHasReturn 15 | case object SendSerialization 16 | 17 | case class JoinEvt( 18 | id: Long, 19 | name: String 20 | ) 21 | 22 | class LocalActor extends Actor { 23 | 24 | val path = 25 | ConfigFactory.defaultApplication().getString("remote.actor.name.test") 26 | implicit val timeout = Timeout(4.seconds) 27 | 28 | val remoteActor = context.actorSelection(path) 29 | 30 | def receive: Receive = { 31 | case Init => "init local actor" 32 | case SendNoReturn => remoteActor ! "hello remote actor" 33 | case SendHasReturn => 34 | for { 35 | r <- remoteActor.ask("hello remote actor") 36 | } yield println(r) 37 | 38 | case SendSerialization => 39 | for { 40 | r <- remoteActor.ask(JoinEvt(1L,"godpan")) 41 | } yield println(r) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Example_06/local/src/main/scala-2.11/LocalDemo.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.{ActorSystem, Props} 2 | 3 | import scala.io.StdIn 4 | 5 | object LocalDemo extends App { 6 | 7 | implicit val system = ActorSystem("LocalDemoSystem") 8 | 9 | //val localActorUsingIdentity = system.actorOf(Props[LocalActorUsingIdentity], name = "LocalActorUsingIdentity") 10 | val localActor = system.actorOf(Props[LocalActor], name = "LocalActor") 11 | 12 | localActor ! Init 13 | localActor ! SendNoReturn 14 | // localActor ! SendHasReturn 15 | localActor ! SendSerialization 16 | 17 | // StdIn.readLine() 18 | // system.terminate() 19 | // StdIn.readLine() 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Example_06/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.15 -------------------------------------------------------------------------------- /Example_06/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_06/remote/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.15 2 | -------------------------------------------------------------------------------- /Example_06/remote/src/main/java/JoinRmiEvt.java: -------------------------------------------------------------------------------- 1 | import java.io.Serializable; 2 | import java.rmi.Remote; 3 | 4 | /** 5 | * Created by panguansen on 17/8/24. 6 | */ 7 | public class JoinRmiEvt implements Remote , Serializable{ 8 | private static final long serialVersionUID = 1L; 9 | private Long id; 10 | private String name; 11 | 12 | public JoinRmiEvt(Long id, String name) { 13 | this.id = id; 14 | this.name = name; 15 | } 16 | 17 | public Long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Example_06/remote/src/main/java/RemoteRMIServer.java: -------------------------------------------------------------------------------- 1 | import java.net.MalformedURLException; 2 | import java.rmi.AlreadyBoundException; 3 | import java.rmi.Naming; 4 | import java.rmi.RemoteException; 5 | import java.rmi.registry.LocateRegistry; 6 | 7 | /** 8 | * Created by panguansen on 17/8/24. 9 | */ 10 | public class RemoteRMIServer { 11 | public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException, InterruptedException { 12 | System.out.println("the RemoteRMIServer is Starting ..."); 13 | RemoteRmiImpl remoteRmi = new RemoteRmiImpl(); 14 | System.out.println("Binding server implementation to registry"); 15 | LocateRegistry.createRegistry(2553); 16 | Naming.bind("rmi://127.0.0.1:2553/remote_rmi",remoteRmi); 17 | System.out.println("the RemoteRMIServer is Started"); 18 | Thread.sleep(10000000); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Example_06/remote/src/main/java/RemoteRmi.java: -------------------------------------------------------------------------------- 1 | import java.rmi.Remote; 2 | import java.rmi.RemoteException; 3 | 4 | /** 5 | * Created by panguansen on 17/8/24. 6 | */ 7 | public interface RemoteRmi extends Remote { 8 | public void sendNoReturn(String message) throws RemoteException, InterruptedException; 9 | public String sendHasReturn(JoinRmiEvt joinRmiEvt) throws RemoteException; 10 | } 11 | -------------------------------------------------------------------------------- /Example_06/remote/src/main/java/RemoteRmiImpl.java: -------------------------------------------------------------------------------- 1 | import java.rmi.RemoteException; 2 | import java.rmi.server.UnicastRemoteObject; 3 | 4 | /** 5 | * Created by panguansen on 17/8/24. 6 | */ 7 | public class RemoteRmiImpl extends UnicastRemoteObject implements RemoteRmi { 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | public RemoteRmiImpl() throws RemoteException {}; 12 | 13 | @Override 14 | public void sendNoReturn(String message) throws RemoteException, InterruptedException { 15 | Thread.sleep(2000); 16 | // throw new RemoteException(); 17 | } 18 | 19 | @Override 20 | public String sendHasReturn(JoinRmiEvt joinRmiEvt) throws RemoteException { 21 | if (joinRmiEvt.getId() >= 0) 22 | return new StringBuilder("the").append(joinRmiEvt.getName()).append("has join").toString(); 23 | else return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Example_06/remote/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | actor { 3 | provider = "akka.remote.RemoteActorRefProvider" 4 | serializers { 5 | kryo = "com.twitter.chill.akka.AkkaSerializer" 6 | } 7 | serialization-bindings { 8 | // "java.io.Serializable" = none 9 | "scala.Product" = kryo 10 | } 11 | } 12 | remote { 13 | enabled-transports = ["akka.remote.netty.tcp"] 14 | netty.tcp { 15 | hostname = "127.0.0.1" 16 | port = 4444 17 | } 18 | log-sent-messages = on 19 | log-received-messages = on 20 | } 21 | } -------------------------------------------------------------------------------- /Example_06/remote/src/main/scala-2.11/RemoteActor.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.Actor 2 | 3 | case class JoinEvt( 4 | id: Long, 5 | name: String 6 | ) 7 | 8 | class RemoteActor extends Actor { 9 | def receive = { 10 | case j: JoinEvt => sender() ! s"the ${j.name} has Join" 11 | case msg: String => 12 | println(s"RemoteActor received message '$msg'") 13 | sender ! "Hello from the RemoteActor" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Example_06/remote/src/main/scala-2.11/RemoteDemo.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.{Props, ActorSystem} 2 | 3 | import scala.io.StdIn 4 | 5 | object RemoteDemo extends App { 6 | val system = ActorSystem("RemoteDemoSystem") 7 | val remoteActor = system.actorOf(Props[RemoteActor], name = "RemoteActor") 8 | remoteActor ! "The RemoteActor is alive" 9 | StdIn.readLine() 10 | system.terminate() 11 | StdIn.readLine() 12 | } 13 | -------------------------------------------------------------------------------- /Example_06/src/main/scala/Test.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by panguansen on 17/8/9. 3 | */ 4 | object Test extends App { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /Example_07/Images.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/godpan/akka-demo/639cf5f40a6605fc39abc3aa013f59d35d0b1be6/Example_07/Images.docx -------------------------------------------------------------------------------- /Example_07/README.txt: -------------------------------------------------------------------------------- 1 | In order to run this you should run thins in the following order 2 | 3 | 1. sample.cluster.transformation.frontend.TransformationFrontendApp command line arg 2551 4 | 2. sample.cluster.transformation.backend.TransformationBackendApp command line arg 2552 5 | 3. sample.cluster.transformation.backend.TransformationBackendApp 6 | 4. sample.cluster.transformation.backend.TransformationBackendApp 7 | 5. sample.cluster.transformation.frontend.TransformationFrontendApp 8 | 9 | 10 | 11 | ClusterClient 12 | 13 | https://groups.google.com/forum/#!topic/akka-user/rqSqh82fimE 14 | Future future = Patterns.ask(clusterClient, new ClusterClient.Send(ClusterActorPath, message, true), timeout) 15 | 16 | https://gist.github.com/phoenix24/6097895 17 | 18 | http://blog.michaelhamrah.com/2014/02/using-akkas-clusterclient/ 19 | 20 | 21 | 22 | Distributed workers 23 | http://www.lightbend.com/activator/template/akka-distributed-workers?_ga=1.183640678.1129354442.1469166689 -------------------------------------------------------------------------------- /Example_07/backend/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | #//#snippet 2 | akka { 3 | actor { 4 | provider = "akka.cluster.ClusterActorRefProvider" 5 | } 6 | remote { 7 | log-remote-lifecycle-events = off 8 | netty.tcp { 9 | hostname = "127.0.0.1" 10 | port = 0 11 | } 12 | } 13 | 14 | cluster { 15 | seed-nodes = [ 16 | "akka.tcp://ClusterSystem@127.0.0.1:2551"] 17 | 18 | roles = [backend] 19 | #//#snippet 20 | # excluded from snippet 21 | auto-down-unreachable-after = 10s 22 | #//#snippet 23 | # auto downing is NOT safe for production deployments. 24 | # you may want to use it during development, read more about it in the docs. 25 | # 26 | } 27 | 28 | } 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Example_07/backend/src/main/scala-2.11/sample/cluster/transformation/backend/TransformationBackend.scala: -------------------------------------------------------------------------------- 1 | package sample.cluster.transformation.backend 2 | 3 | import sample.cluster.transformation.{BackendRegistration, TransformationJob, TransformationResult} 4 | 5 | import language.postfixOps 6 | import scala.concurrent.duration._ 7 | import akka.actor.Actor 8 | import akka.actor.RootActorPath 9 | import akka.cluster.Cluster 10 | import akka.cluster.ClusterEvent.{CurrentClusterState, MemberEvent, MemberUp} 11 | import akka.cluster.Member 12 | import akka.cluster.MemberStatus 13 | 14 | 15 | class TransformationBackend extends Actor { 16 | 17 | val cluster = Cluster(context.system) 18 | 19 | override def preStart(): Unit = cluster.subscribe(self, classOf[MemberEvent]) //在启动Actor时将该节点订阅到集群中 20 | override def postStop(): Unit = cluster.unsubscribe(self) 21 | 22 | def receive = { 23 | case TransformationJob(text) => { 24 | val result = text.toUpperCase // 任务执行得到结果(将字符串转换为大写) 25 | sender() ! TransformationResult(text.toUpperCase) // 向发送者返回结果 26 | } 27 | case state: CurrentClusterState => 28 | state.members.filter(_.status == MemberStatus.Up) foreach register // 根据节点状态向集群客户端注册 29 | case MemberUp(m) => register(m) // 将刚处于Up状态的节点向集群客户端注册 30 | } 31 | 32 | def register(member: Member): Unit = { //将节点注册到集群客户端 33 | context.actorSelection(RootActorPath(member.address) / "user" / "frontend") ! 34 | BackendRegistration 35 | } 36 | } -------------------------------------------------------------------------------- /Example_07/backend/src/main/scala-2.11/sample/cluster/transformation/backend/TransformationBackendApp.scala: -------------------------------------------------------------------------------- 1 | package sample.cluster.transformation.backend 2 | 3 | import language.postfixOps 4 | import scala.concurrent.duration._ 5 | import akka.actor.ActorSystem 6 | import akka.actor.Props 7 | import com.typesafe.config.ConfigFactory 8 | 9 | object TransformationBackendApp { 10 | def main(args: Array[String]): Unit = { 11 | // Override the configuration of the port when specified as program argument 12 | val port = if (args.isEmpty) "2553" else args(0) 13 | val config = ConfigFactory.parseString(s"akka.remote.netty.tcp.port=$port"). 14 | withFallback(ConfigFactory.load()) 15 | 16 | val system = ActorSystem("ClusterSystem", config) 17 | system.actorOf(Props[TransformationBackend], name = "backend") 18 | } 19 | } -------------------------------------------------------------------------------- /Example_07/build.sbt: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import sbt.Keys._ 3 | 4 | 5 | lazy val allResolvers = Seq( 6 | "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/", 7 | "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/" 8 | ) 9 | 10 | val akkaVersion = "2.5.3" 11 | 12 | lazy val AllLibraryDependencies = 13 | Seq( 14 | "com.typesafe.akka" %% "akka-actor" % akkaVersion, 15 | "com.typesafe.akka" %% "akka-remote" % akkaVersion, 16 | "com.typesafe.akka" %% "akka-cluster" % akkaVersion, 17 | "com.typesafe.akka" %% "akka-cluster-tools" % akkaVersion, 18 | "com.typesafe.akka" %% "akka-contrib" % akkaVersion, 19 | "com.twitter" %% "chill-akka" % "0.8.4" 20 | ) 21 | 22 | 23 | lazy val commonSettings = Seq( 24 | version := "1.0", 25 | scalaVersion := "2.11.8", 26 | resolvers := allResolvers, 27 | libraryDependencies := AllLibraryDependencies 28 | ) 29 | 30 | 31 | lazy val root =(project in file(".")). 32 | settings(commonSettings: _*). 33 | settings( 34 | name := "Base" 35 | ) 36 | .aggregate(common, frontend, backend) 37 | .dependsOn(common, frontend, backend) 38 | 39 | lazy val common = (project in file("common")). 40 | settings(commonSettings: _*). 41 | settings( 42 | name := "common" 43 | ) 44 | 45 | lazy val frontend = (project in file("frontend")). 46 | settings(commonSettings: _*). 47 | settings( 48 | name := "frontend" 49 | ) 50 | .aggregate(common) 51 | .dependsOn(common) 52 | 53 | lazy val backend = (project in file("backend")). 54 | settings(commonSettings: _*). 55 | settings( 56 | name := "backend" 57 | ) 58 | .aggregate(common) 59 | .dependsOn(common) -------------------------------------------------------------------------------- /Example_07/common/src/main/scala-2.11/sample/cluster/transformation/TransformationMessages.scala: -------------------------------------------------------------------------------- 1 | package sample.cluster.transformation 2 | 3 | final case class TransformationJob(text: String) // 任务内容 4 | final case class TransformationResult(text: String) // 执行任务结果 5 | final case class JobFailed(reason: String, job: TransformationJob) //任务失败相应原因 6 | case object BackendRegistration // 后台具体执行任务节点注册事件 7 | -------------------------------------------------------------------------------- /Example_07/frontend/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.15 2 | -------------------------------------------------------------------------------- /Example_07/frontend/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | #//#snippet 2 | akka { 3 | actor { 4 | provider = "akka.cluster.ClusterActorRefProvider" 5 | } 6 | remote { 7 | log-remote-lifecycle-events = off 8 | netty.tcp { 9 | hostname = "127.0.0.1" 10 | port = 0 11 | } 12 | } 13 | 14 | cluster { 15 | seed-nodes = [ 16 | "akka.tcp://ClusterSystem@127.0.0.1:2551"] 17 | 18 | roles = [frontend] 19 | 20 | #//#snippet 21 | # excluded from snippet 22 | auto-down-unreachable-after = 10s 23 | #//#snippet 24 | # auto downing is NOT safe for production deployments. 25 | # you may want to use it during development, read more about it in the docs. 26 | # 27 | # auto-down-unreachable-after = 10s 28 | } 29 | 30 | # enable receptionist at start 31 | extensions = ["akka.cluster.client.ClusterClientReceptionist"] 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /Example_07/frontend/src/main/scala-2.11/sample/cluster/transformation/frontend/TransformationFrontend.scala: -------------------------------------------------------------------------------- 1 | package sample.cluster.transformation.frontend 2 | 3 | import sample.cluster.transformation.{TransformationResult, BackendRegistration, JobFailed, TransformationJob} 4 | import language.postfixOps 5 | import scala.concurrent.Future 6 | import akka.actor.Actor 7 | import akka.actor.ActorRef 8 | import akka.actor.Terminated 9 | import akka.util.Timeout 10 | import scala.concurrent.duration._ 11 | import scala.concurrent.ExecutionContext.Implicits.global 12 | import akka.pattern.pipe 13 | import akka.pattern.ask 14 | 15 | 16 | class TransformationFrontend extends Actor { 17 | 18 | var backends = IndexedSeq.empty[ActorRef] //任务后台节点列表 19 | var jobCounter = 0 20 | 21 | def receive = { 22 | case job: TransformationJob if backends.isEmpty => //目前暂无执行任务节点可用 23 | sender() ! JobFailed("Service unavailable, try again later", job) 24 | 25 | case job: TransformationJob => //执行相应任务 26 | jobCounter += 1 27 | implicit val timeout = Timeout(5 seconds) 28 | val backend = backends(jobCounter % backends.size) //根据相应算法选择执行任务的节点 29 | println(s"the backend is ${backend} and the job is ${job}") 30 | val result = (backend ? job) 31 | .map(x => x.asInstanceOf[TransformationResult]) // 后台节点处理得到结果 32 | result pipeTo sender //向外部系统发送执行结果 33 | 34 | case BackendRegistration if !backends.contains(sender()) => // 添加新的后台任务节点 35 | context watch sender() //监控相应的任务节点 36 | backends = backends :+ sender() 37 | 38 | case Terminated(a) => 39 | backends = backends.filterNot(_ == a) // 移除已经终止运行的节点 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Example_07/frontend/src/main/scala-2.11/sample/cluster/transformation/frontend/TransformationFrontendApp.scala: -------------------------------------------------------------------------------- 1 | package sample.cluster.transformation.frontend 2 | 3 | import language.postfixOps 4 | import akka.actor.ActorSystem 5 | import akka.actor.Props 6 | import com.typesafe.config.ConfigFactory 7 | import akka.cluster.client.ClusterClientReceptionist 8 | 9 | 10 | 11 | object TransformationFrontendApp { 12 | 13 | def main(args: Array[String]): Unit = { 14 | 15 | val port = if (args.isEmpty) "0" else args(0) 16 | val config = ConfigFactory.parseString(s"akka.remote.netty.tcp.port=$port"). 17 | withFallback(ConfigFactory.load()) 18 | 19 | val system = ActorSystem("ClusterSystem", config) 20 | val frontend = system.actorOf(Props[TransformationFrontend], name = "frontend") 21 | ClusterClientReceptionist(system).registerService(frontend) 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /Example_07/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 0.13.15 -------------------------------------------------------------------------------- /Example_07/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /Example_07/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | loglevel = "ERROR" 3 | actor { 4 | provider = "akka.cluster.ClusterActorRefProvider" 5 | serializers { 6 | kryo = "com.twitter.chill.akka.AkkaSerializer" 7 | } 8 | serialization-bindings { 9 | "java.io.Serializable" = none 10 | "scala.Product" = kryo 11 | } 12 | } 13 | 14 | remote { 15 | transport = "akka.remote.netty.NettyRemoteTransport" 16 | log-remote-lifecycle-events = off 17 | netty.tcp { 18 | hostname = "127.0.0.1" 19 | port = 5000 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Example_07/src/main/scala-2.11/ClientJobTransformationSendingActor.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.Actor 2 | import akka.actor.ActorPath 3 | import akka.cluster.client.{ClusterClientSettings, ClusterClient} 4 | import akka.pattern.Patterns 5 | import sample.cluster.transformation.{TransformationResult, TransformationJob} 6 | import akka.util.Timeout 7 | import scala.concurrent.duration._ 8 | import scala.concurrent.ExecutionContext.Implicits.global 9 | import scala.util.{Failure, Success} 10 | 11 | 12 | class ClientJobTransformationSendingActor extends Actor { 13 | 14 | val initialContacts = Set( 15 | ActorPath.fromString("akka.tcp://ClusterSystem@127.0.0.1:2551/system/receptionist")) 16 | val settings = ClusterClientSettings(context.system) 17 | .withInitialContacts(initialContacts) 18 | 19 | val c = context.system.actorOf(ClusterClient.props(settings), "demo-client") 20 | 21 | 22 | def receive = { 23 | case TransformationResult(result) => { 24 | println(s"Client response and the result is ${result}") 25 | } 26 | case Send(counter) => { 27 | val job = TransformationJob("hello-" + counter) 28 | implicit val timeout = Timeout(5 seconds) 29 | val result = Patterns.ask(c,ClusterClient.Send("/user/frontend", job, localAffinity = true), timeout) 30 | 31 | result.onComplete { 32 | case Success(transformationResult) => { 33 | self ! transformationResult 34 | } 35 | case Failure(t) => println("An error has occured: " + t.getMessage) 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Example_07/src/main/scala-2.11/DemoClient.scala: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.atomic.AtomicInteger 2 | 3 | import akka.actor.{ActorSystem, Props} 4 | import akka.util.Timeout 5 | import sample.cluster.transformation.backend.TransformationBackendApp 6 | import sample.cluster.transformation.frontend.TransformationFrontendApp 7 | 8 | import scala.io.StdIn 9 | import scala.concurrent.duration._ 10 | 11 | 12 | object DemoClient { 13 | def main(args : Array[String]) { 14 | 15 | TransformationFrontendApp.main(Seq("2551").toArray) //启动集群客户端 16 | TransformationBackendApp.main(Seq("8001").toArray) //启动三个后台节点 17 | TransformationBackendApp.main(Seq("8002").toArray) 18 | TransformationBackendApp.main(Seq("8003").toArray) 19 | 20 | val system = ActorSystem("OTHERSYSTEM") 21 | val clientJobTransformationSendingActor = 22 | system.actorOf(Props[ClientJobTransformationSendingActor], 23 | name = "clientJobTransformationSendingActor") 24 | 25 | val counter = new AtomicInteger 26 | import system.dispatcher 27 | system.scheduler.schedule(2.seconds, 2.seconds) { //定时发送任务 28 | clientJobTransformationSendingActor ! Send(counter.incrementAndGet()) 29 | } 30 | StdIn.readLine() 31 | system.terminate() 32 | } 33 | } 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Example_07/src/main/scala-2.11/Send.scala: -------------------------------------------------------------------------------- 1 | case class Send(count:Int) 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | some demo for learning akka 2 | 3 | akka series article 4 | 5 | - [Akka系列(一):Akka简介与Actor模型](http://www.godpan.me/2017/03/18/learning-akka-1.html) 6 | - [Akka系列(二):Akka中的Actor系统](http://www.godpan.me/2017/04/02/learning-akka-2.html) 7 | - [Akka系列(三):监管与容错](http://www.godpan.me/2017/04/15/learning-akka-3.html) 8 | - [Akka系列(四):Akka中的共享内存模型](http://www.godpan.me/2017/05/01/learning-akka-4.html) 9 | - [Akka系列(五):Java和Scala中的Future](http://www.godpan.me/2017/05/15/learning-akka-5.html) 10 | - [Akka系列(六):Actor解决了什么问题?](http://www.godpan.me/2017/07/10/learning-akka-6.html) 11 | - [Akka系列(七):Actor持久化之Akka persistence](http://www.godpan.me/2017/07/25/learning-akka-7.html) 12 | - [Akka系列(八):Akka persistence设计理念之CQRS](http://www.godpan.me/2017/07/29/learning-akka-8.html) 13 | - [Akka系列(九):Akka分布式之Akka Remote](http://www.godpan.me/2017/08/10/learning-akka-9.html) 14 | - [Akka系列(十):Akka集群之Akka Cluster](http://www.godpan.me/2017/09/05/learning-akka-10.html) --------------------------------------------------------------------------------