diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index ddc65c6..1a21c0b 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -3,6 +3,7 @@ name: Publish Package on Release on: release: types: [published] + workflow_dispatch: jobs: publish: @@ -39,7 +40,12 @@ jobs: mkdir -p ~/.sbt/1.0 echo "credentials += Credentials(\"GitHub Package Registry\", \"maven.pkg.github.com\", \"${{ github.actor }}\", \"${{ secrets.GITHUB_TOKEN }}\")" >> ~/.sbt/1.0/global.sbt - - name: Build and publish - run: sbt clean compile publish + - name: Build and publish for Scala 2.13 + run: sbt ++2.13.12 clean compile publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and publish for Scala 3 + run: sbt ++3.3.0 clean compile publish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index a072f31..c97db40 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -1,8 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - name: Scala CI on: @@ -10,6 +5,7 @@ on: branches: [ "main" ] pull_request: branches: [ "main" ] + workflow_dispatch: permissions: contents: read @@ -23,17 +19,38 @@ jobs: pull-requests: write repository-projects: write steps: - - uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - cache: 'sbt' - - name: Run tests - run: sbt test - # Optional: This step uploads information to the GitHub dependency graph and unblocking Dependabot alerts for the repository - - name: Sbt Dependency Submission - uses: scalacenter/sbt-dependency-submission@v3.0.1 + - uses: actions/checkout@v4 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: 'sbt' + + - name: Cache sbt + uses: actions/cache@v2 + with: + path: ~/.sbt + key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }} + restore-keys: | + ${{ runner.os }}-sbt- + + - name: Cache Coursier + uses: actions/cache@v2 + with: + path: ~/.coursier + key: ${{ runner.os }}-coursier-${{ hashFiles('**/build.sbt') }} + restore-keys: | + ${{ runner.os }}-coursier- + + - name: Run tests for Scala 2.13 + run: sbt ++2.13.12 clean compile test + + - name: Run tests for Scala 3 + run: sbt ++3.3.0 clean compile test + - name: Sbt Dependency Submission for Scala 2.13 + uses: scalacenter/sbt-dependency-submission@v3.0.1 + - name: Sbt Dependency Submission for Scala 3 + uses: scalacenter/sbt-dependency-submission@v3.0.1 diff --git a/.gitignore b/.gitignore index 61bf345..bbc591b 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,5 @@ project/**/metals.sbt .bsp .history +scala2/target +scala3/target diff --git a/README.md b/README.md index 0fa6cf5..1c0da98 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Add the following to your `build.sbt`: ```scala resolvers += "jitpack" at "https://jitpack.io" -libraryDependencies += "com.github.suprnation" % "cats-actors" % "2.0.0-RC1" +libraryDependencies += "com.github.suprnation" &% "cats-actors" % "2.0.0-RC2" ``` #### Using Maven @@ -110,6 +110,8 @@ Add the following to your `pom.xml`: com.github.suprnation cats-actors_2.13 + or + cats-actors_3 2.0.0-RC1 ``` diff --git a/build.sbt b/build.sbt index 4e17e89..01d8d75 100644 --- a/build.sbt +++ b/build.sbt @@ -1,41 +1,68 @@ -ThisBuild / version := "2.0.0-RC1" - -ThisBuild / scalaVersion := "2.13.12" - -addCompilerPlugin("org.typelevel" % "kind-projector" % "0.13.2" cross CrossVersion.full) - ThisBuild / organization := "com.suprnation" ThisBuild / name := "cats-actors" +ThisBuild / version := "2.0.0-RC2" +ThisBuild / organizationName := "SuprNation" +ThisBuild / startYear := Some(2024) +ThisBuild / licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.txt")) -organizationName := "SuprNation" -startYear := Some(2024) -licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.txt")) +ThisBuild / crossScalaVersions := Seq("2.13.12", "3.3.0") +ThisBuild / scalaVersion := crossScalaVersions.value.head -Test / parallelExecution := false +lazy val commonSettings = Seq( + Test / parallelExecution := false, + libraryDependencies ++= Seq( + "org.typelevel" %% "cats-effect" % "3.5.2", + "org.scalatest" %% "scalatest" % "3.2.19" % Test + ), + publishTo := { + val owner = "suprnation" + val repo = "cats-actors" + if (isSnapshot.value) + Some("GitHub Package Registry".at(s"https://maven.pkg.github.com/$owner/$repo")) + else + Some("GitHub Package Registry".at(s"https://maven.pkg.github.com/$owner/$repo")) + } + +) -scalacOptions ++= Seq( // use ++= to add to existing options - "-deprecation", - "-encoding", - "utf8", // if an option takes an arg, supply it on the same line - "-feature", // then put the next option on a new line for easy editing - "-language:implicitConversions", - "-language:existentials", - "-unchecked", - "-Werror", - "-Xlint" // exploit "trailing comma" syntax so you can add an option without editing this line +lazy val scala2Settings = Seq( + libraryDependencies += "org.typelevel" %% "kind-projector" % "0.13.2" cross CrossVersion.full, + scalacOptions ++= Seq( + "-language:implicitConversions", + "-language:existentials" + ) ) -libraryDependencies ++= Seq( - "org.typelevel" %% "cats-effect" % "3.5.2", // if needed for other dependencies - "org.typelevel" %% "cats-effect" % "3.5.0", - "org.scalatest" %% "scalatest" % "3.2.18" % Test +lazy val scala3Settings = Seq( + // Scala 3 specific settings can be added here ) -publishTo := { - val owner = "suprnation" - val repo = "cats-actors" - if (isSnapshot.value) - Some("GitHub Package Registry".at(s"https://maven.pkg.github.com/$owner/$repo")) - else - Some("GitHub Package Registry".at(s"https://maven.pkg.github.com/$owner/$repo")) -} +lazy val root = (project in file(".")) + .settings(commonSettings) + .settings( + name := "cats_actors", + // Conditionally apply settings based on Scala version + libraryDependencies ++= (scalaVersion.value match { + case v if v.startsWith("2.") => Seq("org.typelevel" %% "kind-projector" % "0.13.2" cross CrossVersion.full) + case _ => Seq() + }), + scalacOptions ++= (scalaVersion.value match { + case v if v.startsWith("2.") => Seq( + "-deprecation", + "-encoding", "utf8", + "-feature", + "-unchecked", + "-Werror", + "-language:implicitConversions", + "-language:existentials", + "-Xlint" + ) + case _ => Seq() + }), + Compile / unmanagedSourceDirectories ++= Seq( + baseDirectory.value / "src" / "main" / "scala" + ), + Test / unmanagedSourceDirectories ++= Seq( + baseDirectory.value / "src" / "test" / "scala" + ) + ) diff --git a/src/main/scala/com/suprnation/EscalatingReplyingActor.scala b/src/main/scala/com/suprnation/EscalatingReplyingActor.scala index 7c4bf17..cdd6e2d 100644 --- a/src/main/scala/com/suprnation/EscalatingReplyingActor.scala +++ b/src/main/scala/com/suprnation/EscalatingReplyingActor.scala @@ -17,8 +17,8 @@ package com.suprnation import cats.Parallel -import cats.effect.std.Console -import cats.effect.{Async, Concurrent, Sync, Temporal} +import cats.effect._ +import cats.effect.std._ import cats.implicits._ import com.suprnation.actor.Actor.ReplyingReceive import com.suprnation.actor.SupervisorStrategy.Escalate diff --git a/src/main/scala/com/suprnation/actor/Actor.scala b/src/main/scala/com/suprnation/actor/Actor.scala index 1c16920..d2d8baf 100644 --- a/src/main/scala/com/suprnation/actor/Actor.scala +++ b/src/main/scala/com/suprnation/actor/Actor.scala @@ -67,7 +67,7 @@ object ReplyingActor { ): Actor[F, Request] = withReceive(Behaviour.ignoringBehaviour(name)) - def withReceive[F[+_]: Parallel: Concurrent: Temporal, Request, Response]( + private def withReceive[F[+_]: Parallel: Concurrent: Temporal, Request, Response]( _receive: PartialFunction[Request, F[Response]] ): ReplyingActor[F, Request, Response] = new ReplyingActor[F, Request, Response] { override def receive: ReplyingReceive[F, Request, Response] = _receive @@ -112,7 +112,7 @@ abstract class ReplyingActor[F[+_]: Concurrent: Parallel: Temporal, Request, Res // We do this because we do not want a Ref for the context to make the DX easier. // We also do not want a Ref on self to make the DX easier. implicit val context: ActorContext[F, Request, Response] = null - final val self: ReplyingActorRef[F, Request, Response] = null + val self: ReplyingActorRef[F, Request, Response] = null implicit def implicitSelf: Option[ReplyingActorRef[F, Request, Response]] = Option(self) def init: F[Unit] = Concurrent[F].unit @@ -149,7 +149,8 @@ abstract class ReplyingActor[F[+_]: Concurrent: Parallel: Temporal, Request, Res /** User overridable callback.

Is called when a message isn't handled by the current behaviour of the actor by default it fails with either [[com.suprnation.actor.DeathPactException]] (in case of an unhandled [[com.suprnation.actor.Terminated]] message) or publishes an [[com.suprnation.actor.UnhandledMessage]] to the actor system's event stream. */ def unhandled(message: Any): F[Any] = message match { - case Terminated(dead, _) => MonadThrow[F].raiseError(DeathPactException(dead)) + case Terminated(dead, _) => + MonadThrow[F].raiseError(DeathPactException[F](dead.asInstanceOf[NoSendActorRef[F]])) case _ => context.system.eventStream .offer(UnhandledMessage(message, context.sender, self).toString) diff --git a/src/main/scala/com/suprnation/actor/ActorContext.scala b/src/main/scala/com/suprnation/actor/ActorContext.scala index 6a682f3..fbd01c8 100644 --- a/src/main/scala/com/suprnation/actor/ActorContext.scala +++ b/src/main/scala/com/suprnation/actor/ActorContext.scala @@ -79,10 +79,6 @@ object ActorContext { // Here we will call the parent to handle this.. _self match { case local: InternalActorRef[F, ?, ?] => local.stop - case unexpected => - MonadThrow[F].raiseError( - new IllegalArgumentException(s"ActorRef is not internal: $unexpected") - ) } } else { Concurrent[F].raiseError( @@ -97,41 +93,26 @@ object ActorContext { self match { case local: InternalActorRef[F, ?, ?] => local.assertCellActiveAndDo(_.watch(actorRef, onTerminated)) - case unexpected => - MonadThrow[F].raiseError( - new IllegalArgumentException(s"ActorRef is not internal: $unexpected") - ) // Done for completeness } def unwatch(actorRef: NoSendActorRef[F]): F[NoSendActorRef[F]] = self match { case local: InternalActorRef[F, ?, ?] => local.assertCellActiveAndDo(_.unwatch(actorRef)) - case unexpected => - MonadThrow[F].raiseError( - new IllegalArgumentException(s"ActorRef is not internal: $unexpected") - ) // Done for completeness } override def setReceiveTimeout(timeout: FiniteDuration, onTimeout: => Request): F[Unit] = self match { case local: InternalActorRef[F, ?, ?] => local.assertCellActiveAndDo(_.setReceiveTimeout(timeout, onTimeout)) - case unexpected => - MonadThrow[F].raiseError( - new IllegalArgumentException(s"ActorRef is not internal: $unexpected") - ) // Done for completeness } override val cancelReceiveTimeout: F[Unit] = - Temporal[F].delay(self).flatMap { - case local: InternalActorRef[F, ?, ?] => + Temporal[F] + .delay(self) + .flatMap((local: InternalActorRef[F, ?, ?]) => local.assertCellActiveAndDo(_.cancelReceiveTimeout) - case unexpected => - MonadThrow[F].raiseError( - new IllegalArgumentException(s"ActorRef is not internal: $unexpected") - ) // Done for completeness - } + ) override def replyingActorOf[ChildRequest, ChildResponse]( props: F[ReplyingActor[F, ChildRequest, ChildResponse]], diff --git a/src/main/scala/com/suprnation/actor/ChildStats.scala b/src/main/scala/com/suprnation/actor/ChildStats.scala index 5138410..de223c1 100644 --- a/src/main/scala/com/suprnation/actor/ChildStats.scala +++ b/src/main/scala/com/suprnation/actor/ChildStats.scala @@ -51,8 +51,8 @@ final case class ChildRestartStats[F[+_]]( */ val retriesDone = maxNrOfRetriesCount + 1 val now = System.nanoTime - val windowStart = - if (restartTimeWindowStartNanos == 0) { + val windowStart: Long = + if (restartTimeWindowStartNanos == 0L) { restartTimeWindowStartNanos = now now } else restartTimeWindowStartNanos diff --git a/src/main/scala/com/suprnation/actor/Exceptions.scala b/src/main/scala/com/suprnation/actor/Exceptions.scala index 5640331..d85452e 100644 --- a/src/main/scala/com/suprnation/actor/Exceptions.scala +++ b/src/main/scala/com/suprnation/actor/Exceptions.scala @@ -120,11 +120,11 @@ final case class PostRestartException[F[+_]]( /** InvalidMessageException is thrown when an invalid message is sent to an Actor; Currently only `null` is an invalid message. */ -final case class InvalidMessageException private (message: String) extends AkkaException(message) +final case class InvalidMessageException(message: String) extends AkkaException(message) /** A DeathPactException is thrown by an Actor that receives a Terminated(someActor) message that it doesn't handle itself, effectively crashing the Actor and escalating to the supervisor. */ -final case class DeathPactException[F[+_]] private (dead: NoSendActorRef[F]) +final case class DeathPactException[F[+_]](dead: NoSendActorRef[F]) extends AkkaException("Monitored actor [" + dead + "] terminated") with NoStackTrace diff --git a/src/main/scala/com/suprnation/actor/FiberActorRefProvider.scala b/src/main/scala/com/suprnation/actor/FiberActorRefProvider.scala index 22d32e7..ae9f968 100644 --- a/src/main/scala/com/suprnation/actor/FiberActorRefProvider.scala +++ b/src/main/scala/com/suprnation/actor/FiberActorRefProvider.scala @@ -18,7 +18,7 @@ package com.suprnation.actor import cats.effect.std.{Console, Supervisor} import cats.effect.{Async, Deferred, Temporal} import cats.implicits._ -import cats.{Applicative, Parallel} +import cats.Applicative import com.suprnation.actor.Actor.Actor import com.suprnation.actor.ActorRef.{ActorRef, NoSendActorRef} import com.suprnation.actor.engine.ActorCell @@ -121,7 +121,7 @@ trait ActorRefProvider[F[+_]] { ): F[ReplyingActorRef[F, Request, Response]] } -class LocalActorRefProvider[F[+_]: Parallel: Async: Temporal: Console]( +class LocalActorRefProvider[F[+_]: Async: Temporal: Console]( supervisor: Supervisor[F], systemShutdownSignal: Deferred[F, Unit], system: ActorSystem[F], diff --git a/src/main/scala/com/suprnation/actor/ReplyingActorRef.scala b/src/main/scala/com/suprnation/actor/ReplyingActorRef.scala index c57e8f4..c6faa4d 100644 --- a/src/main/scala/com/suprnation/actor/ReplyingActorRef.scala +++ b/src/main/scala/com/suprnation/actor/ReplyingActorRef.scala @@ -19,7 +19,7 @@ package com.suprnation.actor import cats.effect._ import cats.effect.std.{Console, Supervisor} import cats.syntax.all._ -import cats.{Monad, Parallel} +import cats.Monad import com.suprnation.actor.ActorRef.{ActorRef, NoSendActorRef} import com.suprnation.actor.engine.ActorCell @@ -170,7 +170,7 @@ trait ReplyingActorRef[F[+_], -Request, +Response] { } object InternalActorRef { - def apply[F[+_]: Parallel: Async: Temporal: Console, Request, Response]( + def apply[F[+_]: Async: Temporal: Console, Request, Response]( supervisor: Supervisor[F], systemShutdownSignal: Deferred[F, Unit], name: String, @@ -204,7 +204,7 @@ object InternalActorRef { } yield localActorRef } -case class InternalActorRef[F[+_]: Parallel: Async: Temporal: Console, Request, Response]( +case class InternalActorRef[F[+_]: Async: Temporal: Console, Request, Response]( supervisor: Supervisor[F], systemShutdownSignal: Deferred[F, Unit], name: String, diff --git a/src/main/scala/com/suprnation/actor/dungeon/Children.scala b/src/main/scala/com/suprnation/actor/dungeon/Children.scala index 8a6e45a..e996f5b 100644 --- a/src/main/scala/com/suprnation/actor/dungeon/Children.scala +++ b/src/main/scala/com/suprnation/actor/dungeon/Children.scala @@ -16,7 +16,6 @@ package com.suprnation.actor.dungeon -import cats.Parallel import cats.effect.std.{Semaphore, Supervisor} import cats.effect.{Concurrent, Deferred, Ref} import cats.implicits._ @@ -47,9 +46,6 @@ object Children { trait Children[F[+_], Request, Response] { self: ActorCell[F, Request, Response] => - - implicit val parallelF: Parallel[F] - implicit val concurrentF: Concurrent[F] implicit val childrenContext: ChildrenContext[F] def resumeChildren(causedByFailure: Option[Throwable], perp: Option[NoSendActorRef[F]]): F[Unit] = diff --git a/src/main/scala/com/suprnation/actor/dungeon/Creation.scala b/src/main/scala/com/suprnation/actor/dungeon/Creation.scala index 8a8ef16..80dd118 100644 --- a/src/main/scala/com/suprnation/actor/dungeon/Creation.scala +++ b/src/main/scala/com/suprnation/actor/dungeon/Creation.scala @@ -15,7 +15,7 @@ */ package com.suprnation.actor.dungeon -import cats.effect.{Async, Concurrent, Temporal} +import cats.effect.{Async, Concurrent} import cats.implicits._ import com.suprnation.actor.Actor.ReplyingReceive import com.suprnation.actor.ActorRef.NoSendActorRef @@ -53,8 +53,6 @@ trait Creation[F[+_], Request, Response] { import Creation._ - implicit val asyncF: Async[F] - implicit val temporalF: Temporal[F] implicit val creationContext: CreationContext[F, Request, Response] def create(failure: Option[ActorInitializationException[F]]): F[Unit] = { diff --git a/src/main/scala/com/suprnation/actor/dungeon/DeathWatch.scala b/src/main/scala/com/suprnation/actor/dungeon/DeathWatch.scala index 567f44a..8f557f8 100644 --- a/src/main/scala/com/suprnation/actor/dungeon/DeathWatch.scala +++ b/src/main/scala/com/suprnation/actor/dungeon/DeathWatch.scala @@ -16,8 +16,8 @@ package com.suprnation.actor.dungeon +import cats.effect.Ref import cats.effect.kernel.Concurrent -import cats.effect.{Async, Ref} import cats.syntax.all._ import cats.effect.syntax.all._ import com.suprnation.actor.ActorRef.NoSendActorRef @@ -50,8 +50,6 @@ trait DeathWatch[F[+_], Request, Response] { self: ActorCell[F, Request, Response] => val deathWatchContext: DeathWatchContext[F, Request] - implicit val concurrentF: Concurrent[F] - implicit val asyncF: Async[F] def isWatching(ref: NoSendActorRef[F]): F[Boolean] = deathWatchContext.watchingRef.get.map(_ contains ref) diff --git a/src/main/scala/com/suprnation/actor/dungeon/Dispatch.scala b/src/main/scala/com/suprnation/actor/dungeon/Dispatch.scala index 7d53788..fc3bc14 100644 --- a/src/main/scala/com/suprnation/actor/dungeon/Dispatch.scala +++ b/src/main/scala/com/suprnation/actor/dungeon/Dispatch.scala @@ -16,14 +16,12 @@ package com.suprnation.actor.dungeon -import cats.effect.kernel.Concurrent import cats.effect.std.Console import cats.effect.{Async, Deferred, Temporal} import cats.syntax.all._ import com.suprnation.actor.Exception.Catcher import com.suprnation.actor.dispatch._ import com.suprnation.actor.dispatch.mailbox.{Mailbox, Mailboxes} -import com.suprnation.actor.dungeon.Dispatch.DispatchContext import com.suprnation.actor.engine.ActorCell import com.suprnation.actor.event.Error import com.suprnation.actor.{Envelope, EnvelopeWithDeferred, SystemMessageEnvelope} @@ -66,11 +64,6 @@ object Dispatch { trait Dispatch[F[+_], Request, Response] { actorCell: ActorCell[F, Request, Response] => - implicit val asyncF: Async[F] - implicit val concurrentF: Concurrent[F] - implicit val dispatchContext: DispatchContext[F, Any, Any] - implicit val consoleF: Console[F] - /** Initialise the cell, i.e. setup the mailboxes and supervision. The UID must be reasonably different from the previous UID of a possible ctor with the same path. */ def init(sendSupervise: Boolean): F[Unit] = diff --git a/src/main/scala/com/suprnation/actor/dungeon/FaultHandling.scala b/src/main/scala/com/suprnation/actor/dungeon/FaultHandling.scala index 83e2928..f4e4bbd 100644 --- a/src/main/scala/com/suprnation/actor/dungeon/FaultHandling.scala +++ b/src/main/scala/com/suprnation/actor/dungeon/FaultHandling.scala @@ -56,9 +56,7 @@ trait FaultHandling[F[+_], Request, Response] { import FaultHandling._ - implicit val concurrentF: Concurrent[F] implicit val faultHandlingContext: FaultHandlingContext[F] - val terminatedChildrenContainer: ChildrenContainer[F] = TerminatedChildrenContainer[F]() /* ================= diff --git a/src/main/scala/com/suprnation/actor/dungeon/Suspension.scala b/src/main/scala/com/suprnation/actor/dungeon/Suspension.scala index 857b6da..d18248c 100644 --- a/src/main/scala/com/suprnation/actor/dungeon/Suspension.scala +++ b/src/main/scala/com/suprnation/actor/dungeon/Suspension.scala @@ -17,14 +17,10 @@ package com.suprnation.actor.dungeon import cats.syntax.all._ -import cats.effect.kernel.Concurrent -import com.suprnation.actor.dungeon.Dispatch.DispatchContext import com.suprnation.actor.engine.ActorCell trait Suspension[F[+_], Request, Response] { self: ActorCell[F, Request, Response] => - val dispatchContext: DispatchContext[F, Any, Any] - val concurrentF: Concurrent[F] def resumeNonRecursive: F[Unit] = (actorOp >>= (_.fold(concurrentF.unit)(a => a.aroundPreResume()))) >> diff --git a/src/main/scala/com/suprnation/actor/engine/ActorCell.scala b/src/main/scala/com/suprnation/actor/engine/ActorCell.scala index f2da5c9..56d814a 100644 --- a/src/main/scala/com/suprnation/actor/engine/ActorCell.scala +++ b/src/main/scala/com/suprnation/actor/engine/ActorCell.scala @@ -18,13 +18,14 @@ package com.suprnation.actor.engine import cats.Parallel import cats.effect._ +import cats.effect.implicits._ import cats.effect.std.{Console, Supervisor} -import cats.effect.syntax.all._ import cats.syntax.all._ import com.suprnation.actor.Actor.ReplyingReceive import com.suprnation.actor.ActorRef.NoSendActorRef import com.suprnation.actor._ import com.suprnation.actor.dispatch._ +import com.suprnation.actor.dungeon.Dispatch.DispatchContext import com.suprnation.actor.dungeon.ReceiveTimeout import com.suprnation.actor.event.{Debug, LogEvent} import com.suprnation.typelevel.actors.syntax._ @@ -43,7 +44,7 @@ object ActorCell { if (uid == undefinedUid) newUid() else uid } - def apply[F[+_]: Parallel: Async: Temporal: Console, Request, Response]( + def apply[F[+_]: Async: Temporal: Console, Request, Response]( supervisor: Supervisor[F], systemShutdownSignal: Deferred[F, Unit], _self: InternalActorRef[F, Request, Response], @@ -90,7 +91,12 @@ object ActorCell { _dispatchContext override val system: ActorSystem[F] = _actorSystem - override var currentMessage: Option[Envelope[F, ?]] = None + + var _currentMessage: Option[com.suprnation.actor.Envelope[F, Any]] = + Option.empty[com.suprnation.actor.Envelope[F, Any]] + + override def currentMessage: Option[Envelope[F, Any]] = _currentMessage + var _isIdle: Boolean = true val isIdleTrue: F[Unit] = Temporal[F].delay { _isIdle = true } @@ -208,12 +214,12 @@ object ActorCell { } { case EnvelopeWithDeferred(envelope, deferred) => Temporal[F].delay { _isIdle = false - currentMessage = envelope.some + _currentMessage = envelope.some creationContext.senderOp = envelope.sender } >> invoke(envelope).map { case (result, success) => if (success) { - currentMessage = None + _currentMessage = None creationContext.senderOp = None } result @@ -255,7 +261,7 @@ object ActorCell { override def clearActorFields(recreate: Boolean): F[Unit] = Temporal[F].delay { - currentMessage = None + _currentMessage = None creationContext.behaviourStack.clear() } @@ -353,7 +359,15 @@ trait ActorCell[F[+_], Request, Response] with ActorRefProvider[F] { // format: on - var currentMessage: Option[Envelope[F, ?]] + implicit val concurrentF: Concurrent[F] + implicit val asyncF: Async[F] + implicit val parallelF: Parallel[F] + implicit val temporalF: Temporal[F] + implicit val consoleF: Console[F] + + val dispatchContext: DispatchContext[F, Any, Any] + + def currentMessage: Option[Envelope[F, Any]] def context: F[ActorContext[F, Request, Response]] diff --git a/src/main/scala/com/suprnation/actor/event/DeadLetterListener.scala b/src/main/scala/com/suprnation/actor/event/DeadLetterListener.scala index 5fd9755..9f35717 100644 --- a/src/main/scala/com/suprnation/actor/event/DeadLetterListener.scala +++ b/src/main/scala/com/suprnation/actor/event/DeadLetterListener.scala @@ -18,11 +18,10 @@ package com.suprnation.actor.event import cats.Parallel import cats.effect.{Concurrent, Temporal} -import com.suprnation.actor.Actor.Actor -import com.suprnation.actor.ActorLogging +import com.suprnation.actor.{ActorLogging, ReplyingActor} case class DeadLetterListener[F[+_]: Parallel: Concurrent: Temporal]() - extends Actor[F, Any] + extends ReplyingActor[F, Any, Any] with ActorLogging[F, Any] { override def receive: PartialFunction[Any, F[Unit]] = { case message => log(message) diff --git a/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecAllForOne.scala b/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecAllForOne.scala index bccecc6..91d7769 100644 --- a/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecAllForOne.scala +++ b/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecAllForOne.scala @@ -1101,7 +1101,6 @@ class SupervisionSpecAllForOne extends AsyncFlatSpec with Matchers { eventBuffer, deadLetterBuffer ) => - () trackedChildren.size should be(1) parentMessageBuffer._2.size should be(4) parentMessageBuffer._2.toSet should contain.allOf( @@ -1253,7 +1252,6 @@ class SupervisionSpecAllForOne extends AsyncFlatSpec with Matchers { eventBuffer, deadLetterBuffer ) => - () trackedChildren.size should be(4) parentMessageBuffer._2.size should be(4) parentMessageBuffer._2.toSet should contain.allOf( diff --git a/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecOneForOne.scala b/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecOneForOne.scala index 46a9c90..fb1a47f 100644 --- a/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecOneForOne.scala +++ b/src/test/scala/com/suprnation/actor/supervision/SupervisionSpecOneForOne.scala @@ -885,7 +885,6 @@ class SupervisionSpecOneForOne extends AsyncFlatSpec with Matchers { eventBuffer, deadLetterBuffer ) => - () trackedChildren.size should be(1) parentMessageBuffer._2.size should be(4) parentMessageBuffer._2.toSet should contain.allOf( @@ -1038,7 +1037,6 @@ class SupervisionSpecOneForOne extends AsyncFlatSpec with Matchers { eventBuffer, deadLetterBuffer ) => - () trackedChildren.size should be(4) parentMessageBuffer._2.size should be(4) parentMessageBuffer._2.toSet should contain.allOf(