Fixed a critical mistake

Erroneously used functional actor for mutable state.
Changed actor style to OO from functional.
Experimented with ask pattern to get final result
This commit is contained in:
Rohan Sircar 2020-08-19 13:17:23 +05:30
parent 260aa0fdc4
commit 1abc30070c
3 changed files with 45 additions and 28 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.ammonite
.metals

View File

@ -13,35 +13,47 @@ import akka.util.Timeout
import scala.concurrent.duration._
import akka.actor.typed.scaladsl.AskPattern._
import scala.concurrent.ExecutionContext.Implicits.global
import akka.actor.typed.scaladsl.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext
import scala.util.Success
import scala.util.Failure
import scala.concurrent.Await
import scala.concurrent.Future
object CounterActor {
final case class CounterResult(count: Int)
sealed trait Command
final case object IncCount extends Command
final case class CounterResult(count: Int)
final case class GetResult(sender: ActorRef[RootActor.Command])
extends Command
var counter = 0
final case class GetResult(sender: ActorRef[CounterResult]) extends Command
def apply(): Behavior[Command] =
Behaviors.receive { (context, command) =>
command match {
case IncCount => counter += 1
Behaviors.setup(ctx => new CounterActor(ctx))
private class CounterActor(context: ActorContext[Command])
extends AbstractBehavior[Command](context) {
private var counter = 0 // encapsulated mutable state
override def onMessage(msg: Command): Behavior[Command] = {
msg match {
case IncCount =>
counter += 1
Behaviors.same
case GetResult(sender) =>
context.log.info(s"Value of counter is $counter");
sender ! RootActor.Reply(counter)
}
sender ! CounterResult(counter)
Behaviors.same
}
}
}
}
object RootActor {
sealed trait Command
case class Reply[T](reply: T) extends Command
case object Begin extends Command
case object GetResult extends Command
final case class Reply[T](reply: T) extends Command
final case object Begin extends Command
final case class GetResult(repyTo: ActorRef[CounterActor.CounterResult])
extends Command
implicit val timeout: Timeout = 3.seconds
@ -63,10 +75,11 @@ object RootActor {
counterActor ! CounterActor.IncCount
counterActor ! CounterActor.IncCount
case GetResult =>
case GetResult(replyTo) =>
counterActor ! CounterActor.GetResult(
context.self
replyTo
)
}
Behaviors.same
@ -77,13 +90,15 @@ object RootActor {
@main
def main() = {
implicit val rootActor =
implicit val system =
ActorSystem(RootActor(), "TestActors")
implicit val timeout: Timeout = 3.seconds
rootActor ! RootActor.Begin
rootActor ! RootActor.GetResult
system ! RootActor.Begin
// system ! RootActor.GetResult
Thread.sleep(1000)
val x: Future[CounterActor.CounterResult] =
system ? (ref => RootActor.GetResult(ref))
Await.result(x, 1.second)
}

View File

@ -3,15 +3,15 @@
An experiment to see how the actor model can be used to synchronize / encapsulate mutable state without the use of locks.
## Usage
```bash
./ActorsDemo.sc
```
Sample output:
```
22:11:47.473 [TestActors-akka.actor.default-dispatcher-3] INFO ammonite.$file.ActorDemo$RootActor$ - --- Beginning ---
22:11:47.475 [TestActors-akka.actor.default-dispatcher-6] INFO ammonite.$file.ActorDemo$CounterActor$ - Value of counter is 5
22:11:47.475 [TestActors-akka.actor.default-dispatcher-3] INFO ammonite.$file.ActorDemo$RootActor$ - Received message Reply(5)
```
13:02:58.966 [TestActors-akka.actor.default-dispatcher-3] INFO ammonite.$file.AkkaActorsDemo.ActorDemo$RootActor$ - --- Beginning ---
13:02:58.967 [TestActors-akka.actor.default-dispatcher-5] INFO ammonite.$file.AkkaActorsDemo.ActorDemo$CounterActor$CounterActor - Value of counter is 5
CounterResult(5)
```