├── .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 |
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 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
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 |
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 |
--------------------------------------------------------------------------------
/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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
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 |
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 |
--------------------------------------------------------------------------------
/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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
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 |
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 | 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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
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