{"id":21948110,"url":"https://github.com/evolution-gaming/safe-akka","last_synced_at":"2025-04-23T00:16:09.465Z","repository":{"id":41871973,"uuid":"111817597","full_name":"evolution-gaming/safe-akka","owner":"evolution-gaming","description":"Safe Akka","archived":false,"fork":false,"pushed_at":"2025-04-03T10:21:25.000Z","size":278,"stargazers_count":8,"open_issues_count":2,"forks_count":3,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-23T00:16:02.583Z","etag":null,"topics":["akka","persistence","safe"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evolution-gaming.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-23T14:15:17.000Z","updated_at":"2025-04-03T10:21:28.000Z","dependencies_parsed_at":"2025-01-16T18:28:33.940Z","dependency_job_id":"3e3ffa21-dbf6-4fc8-b7e2-faa807fe1673","html_url":"https://github.com/evolution-gaming/safe-akka","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolution-gaming%2Fsafe-akka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolution-gaming%2Fsafe-akka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolution-gaming%2Fsafe-akka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolution-gaming%2Fsafe-akka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evolution-gaming","download_url":"https://codeload.github.com/evolution-gaming/safe-akka/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250343957,"owners_count":21415041,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["akka","persistence","safe"],"created_at":"2024-11-29T05:12:01.466Z","updated_at":"2025-04-23T00:16:09.457Z","avatar_url":"https://github.com/evolution-gaming.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Safe Akka\n[![Build Status](https://github.com/evolution-gaming/safe-akka/workflows/CI/badge.svg)](https://github.com/evolution-gaming/safe-akka/actions?query=workflow%3ACI)\n[![Coverage Status](https://coveralls.io/repos/github/evolution-gaming/safe-akka/badge.svg?branch=master)](https://coveralls.io/github/evolution-gaming/safe-akka?branch=master)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/735356614683409ea3f65e179708c20b)](https://app.codacy.com/gh/evolution-gaming/safe-akka/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade)\n[![Version](https://img.shields.io/badge/version-click-blue)](https://evolution.jfrog.io/artifactory/api/search/latestVersion?g=com.evolutiongaming\u0026a=safe-akka_2.13\u0026repos=public)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellowgreen.svg)](https://opensource.org/licenses/MIT)\n\nThis library provides abstraction on top of akka actors in order to add more type safety\n\n## Actor example\n\n```scala\n  import com.evolutiongaming.safeakka.actor._\n  \n  val ref = SafeActorRef(_ =\u003e (counter(0), ActorLog.empty))\n    \n  ref ! Msg.Inc\n  ref ! Msg.Dec\n  ref ! PoisonPill\n  // ref ! \"test\" - does not compile\n\n  def counter(state: Int): Behavior[Msg] = Behavior.onMsg[Msg] {\n    case Signal.Msg(msg, sender) =\u003e\n      val result = msg match {\n        case Msg.Inc =\u003e state + 1\n        case Msg.Dec =\u003e state - 1\n      }\n      sender ! result\n      counter(result)\n  }\n\n\n  sealed trait Msg\n\n  object Msg {\n    case object Inc extends Msg\n    case object Dec extends Msg\n  }\n```\n\n## PersistentActor example\n\n```scala\ndef persistenceSetup(ctx: ActorCtx) = {\n\n  ctx.setReceiveTimeout(300.millis)\n\n  new PersistenceSetup[Counter, Counter, Cmd, Event] {\n\n    val persistenceId = UUID.randomUUID().toString\n\n    val log = ActorLog.empty\n\n    def journalId = None\n\n    def snapshotId = None\n\n    def onRecoveryStarted(\n      offer: Option[SnapshotOffer[Counter]],\n      journaller: Journaller,\n      snapshotter: Snapshotter[Counter]) = new Recovering {\n\n      def state = offer map { _.snapshot } getOrElse Counter(0, 0)\n\n      def eventHandler(state: Counter, event: Event, seqNr: SeqNr) = state(event, seqNr)\n\n      def onCompleted(state: Counter, seqNr: SeqNr) = {\n\n        def behavior(counter: Counter): Behavior[Cmd, Event] = Behavior[Cmd, Event] { (signal, _) =\u003e\n          signal match {\n            case signal: PersistenceSignal.System =\u003e\n              testActor.tell(signal, ctx.self)\n              signal match {\n                case PersistenceSignal.Sys(Signal.RcvTimeout) =\u003e ctx.setReceiveTimeout(Duration.Inf)\n                case _                                        =\u003e\n              }\n              behavior(counter)\n\n            case PersistenceSignal.Cmd(cmd, sender) =\u003e\n\n              def onEvent(event: Event) = {\n\n                val record = Record.of(event)(_ =\u003e sender.tell(event, ctx.self))\n                val onPersisted = (seqNr: SeqNr) =\u003e {\n                  val newCounter = counter(event, seqNr)\n                  sender.tell(newCounter, ctx.self)\n                  if (cmd == Cmd.Dec) snapshotter.save(seqNr, newCounter)\n                  behavior(newCounter)\n                }\n\n                val onFailure = (failure: Throwable) =\u003e {\n                  sender.tell(Status.Failure(failure), ctx.self)\n                }\n\n                Behavior.persist(Nel(record), onPersisted, onFailure)\n              }\n\n              cmd match {\n                case Cmd.Inc  =\u003e onEvent(Event.Inc)\n                case Cmd.Dec  =\u003e onEvent(Event.Dec)\n                case Cmd.Stop =\u003e Behavior.stop\n                case Cmd.Get  =\u003e\n                  sender.tell(counter, ctx.self)\n                  behavior(counter)\n              }\n          }\n        }\n\n        behavior(state)\n      }\n\n      def onStopped(state: Counter, seqNr: SeqNr) = {}\n    }\n\n    def onStopped(seqNr: SeqNr): Unit = {}\n  }\n}\n\n\nval ref = PersistentActorRef(persistenceSetup)\nref ! Cmd.Get\nref ! Cmd.Inc\nref ! Cmd.Dec\nref ! Cmd.Stop\n\n```\n\nSee [CounterSpec](safe-persistence/src/test/scala/com/evolutiongaming/safeakka/persistence/CounterSpec.scala)\n\n## Setup\n\n```scala\naddSbtPlugin(\"com.evolution\" % \"sbt-artifactory-plugin\" % \"0.0.2\")\n\nlibraryDependencies += \"com.evolutiongaming\" %% \"safe-actor\" % \"3.1.0\"\n\nlibraryDependencies += \"com.evolutiongaming\" %% \"safe-persistence\" % \"3.1.0\"\n\nlibraryDependencies += \"com.evolutiongaming\" %% \"safe-persistence-async\" % \"3.1.0\"\n\nlibraryDependencies += \"com.evolutiongaming\" %% \"safe-persistence-testkit\" % \"3.1.0\"\n``` \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevolution-gaming%2Fsafe-akka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevolution-gaming%2Fsafe-akka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevolution-gaming%2Fsafe-akka/lists"}