{"id":21625373,"url":"https://github.com/eigr/spawn-java-std-sdk","last_synced_at":"2025-07-11T18:34:19.636Z","repository":{"id":191081178,"uuid":"580940486","full_name":"eigr/spawn-java-std-sdk","owner":"eigr","description":"Spawn Java Standalone SDK","archived":false,"fork":false,"pushed_at":"2024-09-23T14:27:33.000Z","size":285,"stargazers_count":3,"open_issues_count":1,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-11T13:04:40.068Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eigr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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,"zenodo":null}},"created_at":"2022-12-21T21:04:22.000Z","updated_at":"2024-09-23T14:27:37.000Z","dependencies_parsed_at":"2024-03-14T21:50:17.390Z","dependency_job_id":"cb584331-bdf5-46f1-861c-f7005969c8d9","html_url":"https://github.com/eigr/spawn-java-std-sdk","commit_stats":null,"previous_names":["eigr/spawn-java-std-sdk"],"tags_count":61,"template":false,"template_full_name":null,"purl":"pkg:github/eigr/spawn-java-std-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-java-std-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-java-std-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-java-std-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-java-std-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eigr","download_url":"https://codeload.github.com/eigr/spawn-java-std-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-java-std-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264870625,"owners_count":23676279,"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":[],"created_at":"2024-11-25T01:08:59.396Z","updated_at":"2025-07-11T18:34:19.589Z","avatar_url":"https://github.com/eigr.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spawn JVM SDK\n[![](https://jitpack.io/v/eigr/spawn-java-std-sdk.svg)](https://jitpack.io/#eigr/spawn-java-std-sdk)\n\nJVM User Language Support for [Spawn](https://github.com/eigr/spawn).\n\n# Table of Contents\n\n1. [Overview](#overview)\n2. [Getting Started](#getting-started)\n   - [Deploy](#deploy)\n3. [Advanced Use Cases](#advanced-use-cases)\n    - [Dependency Injection](#dependency-injection)\n    - [Types of Actors](#types-of-actors)\n    - [Stateless Actors](#stateless-actors)\n    - [Considerations about Spawn actors](#considerations-about-spawn-actors)\n    - [Broadcast](#broadcast)\n    - [Side Effects](#side-effects)\n    - [Forward](#forward)\n    - [Pipe](#pipe)\n    - [State Management](#state-management)\n4. [Using Actors](#using-actors)\n    - [Call Named Actors](#call-named-actors)\n    - [Call Unnamed Actors](#call-unnamed-actors)\n    - [Async](#async)\n    - [Timeouts](#timeouts)\n5. [Deploy](#deploy)\n    - [Defining an ActorSystem](#defining-an-actorsystem)\n    - [Defining an ActorHost](#defining-an-actorhost)\n    - [Activators](#activators)\n6. [Actor Model](#actor-model)\n    - [Virtual Actors](#virtual-actors)\n\n\n## Overview\n\nSpawn is a Stateful Serverless Runtime and Framework based on the [Actor Model](https://youtu.be/7erJ1DV_Tlo) and operates as a Service Mesh.\n\nSpawn's main goal is to remove the complexity in developing services or microservices, providing simple and intuitive APIs, \nas well as a declarative deployment and configuration model and based on a Serverless architecture and Actor Model.\nThis leaves the developer to focus on developing the business domain while the platform deals with the complexities and \ninfrastructure needed to support the scalable, resilient, distributed, and event-driven architecture that modern systems requires.\n\nSpawn is based on the sidecar proxy pattern to provide a polyglot Actor Model framework and platform.\nSpawn's technology stack, built on the [BEAM VM](https://www.erlang.org/blog/a-brief-beam-primer/) (Erlang's virtual machine) \nand [OTP](https://www.erlang.org/doc/design_principles/des_princ.html), provides support for different languages from its native Actor model.\n\nFor more information consult the main repository [documentation](https://github.com/eigr/spawn).\n\n## Getting Started\n\nFirst we need to install spawn cli tool to create a new Java project.\n\n```shell\ncurl -sSL https://github.com/eigr/spawn/releases/download/v1.4.2/install.sh | sh\n```\nNow you will need to fill in the data for groupId, artifactId, version, and package. \nLet's call our maven artifact spawn-java-demo. The output of this command will be similar to the output below\n\n```shell\nspawn new java hello_world --group-id=io.eigr.spawn --artifact-id=spawn-java-demo --version=1.0.0 --package=io.eigr.spawn.java.demo\n```\nNow it is necessary to download the dependencies via Maven:\n\n```shell\ncd spawn-java-demo \u0026\u0026 mvn install\n```\n\nSo far it's all pretty boring and not really Spawn related, so it's time to start playing for real.\nThe first thing we're going to do is define a place to put our protobuf files. \n\n```shell\ntouch src/main/proto/domain/domain.proto\n```\n\nAnd let's populate this file with the following content:\n\n```protobuf\nsyntax = \"proto3\";\n\npackage domain;\n// Due to the dynamic nature of spawn we are required to define the java package \n// as being the same as the protobuf package name.\noption java_package = \"domain\";\n// Generating the java classes in multiple files is mandatory for the process to work correctly.\noption java_multiple_files = true;\n\nmessage State {\n   repeated string languages = 1;\n}\n\nmessage Request {\n   string language = 1;\n}\n\nmessage Reply {\n   string response = 1;\n}\n\nservice JoeActor {\n   rpc SetLanguage(Request) returns (Reply);\n}\n```\n\n\u003e **_NOTE:_** Due to the dynamic nature of spawn we are required to define the java package\n\u003e as being the same as the protobuf package name. Also generating the java classes in multiple files \n\u003e is mandatory for the process to work correctly.\n\nWe must compile this file using the protoc utility. In the root of the project type the following command:\n\n```shell\nmvn protobuf:compile\n```\n\nNow in the spawn-java-demo folder we will create our first Java file containing the code of our Actor.\n\n```shell\ntouch src/main/java/io/eigr/spawn/java/demo/Joe.java\n```\n\nPopulate this file with the following content:\n\n```Java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"JoeActor\"),\n                channel(\"test.channel\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        if (context.getState().isPresent()) {\n            //Do something with previous state\n        }\n\n        return Value.at()\n                .response(Reply.newBuilder()\n                        .setResponse(String.format(\"Hi %s. Hello From Java\", msg.getLanguage()))\n                        .build())\n                .state(updateState(msg.getLanguage()))\n                .reply();\n    }\n\n    private State updateState(String language) {\n        return State.newBuilder()\n                .addLanguages(language)\n                .build();\n    }\n}\n```\n\n### Dissecting the code\n\n***Class Declaration***\n\n```java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport domain.State;\n\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n // ...\n}\n```\n\nThe `JoeActor` class implements `StatefulActor\u003cState\u003e` interface. `StatefulActor` is a generic interface provided by the Spawn API, \nwhich takes a type parameter for the state. In this case, the state type is `domain.State` \ndefined in above protobuf file.\n\n***Configure Actor Behavior***\n\n```java\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n   @Override\n   public ActorBehavior configure(BehaviorCtx context) {\n      return new NamedActorBehavior(\n              name(\"JoeActor\"),\n              channel(\"test.channel\"),\n              action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n      );\n   }\n}\n```\n\nThis `configure` method is overridden from `StatefulActor` and is used to configure the actor's behavior.\n\n* `name(\"JoeActor\")`: Specifies the name of the actor. Note that the Actor name has the same name as the service declared \n                      in protobuf. This is not a coincidence, the Spawn proxy uses the protobuf metadata to map **actors** and \n                      their **actions** and therefore these names should correctly reflect this behavior.\n* `channel(\"test.channel\")`: Specifies the channel the actor listens to. See [Broadcast](#broadcast) section below.\n* `action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))`: Binds the `SetLanguage` action to the `setLanguage` method, \n                                                                                which takes a `Request` message as input. \n                                                                                Where the second parameter of `ActionBindings.of(type, lambda)` method is a lambda.\n\n***Handle request***\n\n```java\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n   //\n   private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n      if (context.getState().isPresent()) {\n         // Do something with the previous state\n      }\n\n      return Value.at()\n              .response(Reply.newBuilder()\n                      .setResponse(String.format(\"Hi %s. Hello From Java\", msg.getLanguage()))\n                      .build())\n              .state(updateState(msg.getLanguage()))\n              .reply();\n   }\n}\n```\n\nThis method `setLanguage` is called when the `SetLanguage` action is invoked. It takes an `ActorContext\u003cState\u003e` and a `Request` message as parameters.\n\n* `context.getState().isPresent()`: Checks if there is a previous existing state.\n* The method then creates a new `Value` response:\n  * `response(Reply.newBuilder().setResponse(...).build())`: Builds a `Reply` object with a response message.\n  * `state(updateState(msg.getLanguage()))`: Updates the state with the new language.\n  * `reply()`: Indicates that this is a reply message. You could also ignore the reply if you used a `noReply()` method instead of the `reply` method.\n\nOk now with our Actor properly defined, we just need to start the SDK correctly. Create another file called App.java \nto serve as your application's entrypoint and fill it with the following content:\n\n```Java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.Spawn;\n\npublic class App {\n   public static void main(String[] args) throws Exception {\n      Spawn spawnSystem = new SpawnSystem()\n              .create(\"spawn-system\")\n              .withActor(Joe.class)\n              .build();\n\n      spawnSystem.start();\n   }\n}\n```\n\nOr passing transport options like:\n\n```Java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.Spawn;\nimport io.eigr.spawn.api.TransportOpts;\n\npublic class App {\n   public static void main(String[] args) throws Exception {\n      TransportOpts opts = TransportOpts.builder()\n              .port(8091)\n              .proxyPort(9003)\n              .executor(Executors.newVirtualThreadPerTaskExecutor()) // If you use java above 19 and use the --enable-preview flag when running the jvm\n              .build();\n\n      Spawn spawnSystem = new SpawnSystem()\n              .create(\"spawn-system\")\n              .withActor(Joe.class)\n              .withTransportOptions(opts)\n              .build();\n\n      spawnSystem.start();\n   }\n}\n```\n\nThen:\n\n```shell\nmvn compile \u0026\u0026 mvn package \u0026\u0026 java -jar target/spawn-java-demo-1.0-SNAPSHOT.jar \n```\n\nBut of course you will need to locally run the Elixir proxy which will actually provide all the functionality for your Java application. \n\n```shell\nspawn dev run -p src/main/proto -s spawn-system -W\n```\n\nSpawn is based on kubernetes and containers, so you will need to generate a docker container for your application.\nThere are many ways to do this, one of them is by adding Maven's jib plugin. \nAdd the following lines to your plugin's section in pom.xml file:\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003ecom.google.cloud.tools\u003c/groupId\u003e\n    \u003cartifactId\u003ejib-maven-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e3.3.2\u003c/version\u003e\n    \u003cconfiguration\u003e\n        \u003cto\u003e\n            \u003cimage\u003eyour-repo-here/spawn-java-demo\u003c/image\u003e\n        \u003c/to\u003e\n    \u003c/configuration\u003e\n\u003c/plugin\u003e\n```\n\nfinally you will be able to create your container by running the following command in the root of your project:\n\n```shell\nmvn compile jib:build\n```\n\nAnd this is it to start! Now that you know the basics of local development, we can go a little further.\n\n### Deploy\n\nPlease see main documentation [page](https://github.com/eigr/spawn/blob/main/docs/getting_started.md).\n\n## Advanced Use Cases\n\nSpawn Actors abstract a huge amount of developer infrastructure and can be used for many types of jobs. \nIn the sections below we will demonstrate some features available in Spawn that contribute to the development of \ncomplex applications in a simplified way.\n\n### Dependency Injection\n\nSometimes we need to pass many arguments as dependencies to the Actor class.\nIn this case, it is more convenient to use your own dependency injection mechanism.\nHowever, the Spawn SDK already comes with an auxiliary class to make this easier for the developer.\nLet's look at an example:\n\n1. First let's take a look at some example dependency classes:\n\n```java\n// We will have an interface that represents any type of service.\npublic interface MessageService {\n   String getDefaultMessage();\n}\n\n// and concrete implementation here\npublic class MessageServiceImpl implements MessageService {\n   @Override\n   public String getDefaultMessage() {\n      return \"Hello Spawn in English\";\n   }\n}\n```\n\n2. Second, let's define an actor so that it receives an instance of the DependencyInjector class through the context of configure method:\n\n```java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.action;\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.name;\n\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n\n    private String defaultMessage;\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        defaultMessage = context.getInjector().getInstance(String.class);\n        return new NamedActorBehavior(\n                name(\"JoeActor\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        return Value.at()\n                .response(Reply.newBuilder()\n                        .setResponse(defaultMessage)\n                        .build())\n                .state(updateState(\"java\"))\n                .reply();\n    }\n\n    private State updateState(String language) {\n        return State.newBuilder()\n                .addLanguages(language)\n                .build();\n    }\n}\n```\n\n3. Then you can pass your dependent classes this way to your Actor:\n```java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.Spawn;\nimport io.eigr.spawn.api.extensions.DependencyInjector;\nimport io.eigr.spawn.api.extensions.SimpleDependencyInjector;\n\npublic class App {\n   public static void main(String[] args) {\n      DependencyInjector injector = SimpleDependencyInjector.createInjector();\n      /* \n      You can bind as many objects as you want. As long as they are of unique types.\n      If you try to add different instances of the same type you will receive an error.        \n      */ \n      injector.bind(MessageService.class, new MessageServiceImpl());\n      \n      // or using alias for put different values of same key types\n      injector.bind(MessageService.class, \"myMessageService\", new MessageServiceImpl());\n\n      Spawn spawnSystem = new Spawn.SpawnSystem()\n              .create(\"spawn-system\", injector)\n              .withActor(Joe.class)\n              .build();\n\n      spawnSystem.start();\n   }\n}\n```\n\nIt is important to note that this helper mechanism does not currently implement any type of complex dependency graph. \nTherefore, it will not build objects based on complex dependencies nor take care of the object lifecycle for you. \nIn other words, all instances added through the bind method of the SimpleDependencyInjector class will be singletons. \nThis mechanism works much more like a bucket of objects that will be forwarded via your actor's context.\n\n\u003e **_NOTE:_** **Why not use the java cdi 2.0 spec?**\nOur goals are to keep the SDK for standalone Java applications very simple. We consider that implementing the entire specification would not be viable for us at the moment. It would be a lot of effort and energy expenditure that we consider spending on other parts of the ecosystem that we think will guarantee us more benefits.\nHowever, as an open source project we will be happy if anyone wants to contribute in this regard.\n\n\n### Types of Actors\n\nFirst we need to understand how the various types of actors available in Spawn behave. Spawn defines the following types of Actors:\n\n* **Named Actors**: Named actors are actors whose name is defined at compile time. They also behave slightly differently \nThen unnamed actors and pooled actors. Named actors when they are defined with the stateful parameter equal to True are \nimmediately instantiated when they are registered at the beginning of the program, they can also only be referenced by \nthe name given to them in their definition.\n\n* **Unnamed Actors**: Unlike named actors, unnamed actors are only created when they are named at runtime, that is, \nduring program execution. Otherwise, they behave like named actors.\n\n* **Pooled Actors**: Pooled Actors, as the name suggests, are a collection of actors that are grouped under the same name \nassigned to them at compile time. Pooled actors are generally used when higher performance is needed and are also \nrecommended for handling serverless loads.\n\n### Stateless Actors\n\nIn addition to these types, Spawn also allows the developer to choose Stateful actors, who need to maintain the state, \nor Stateless, those who do not need to maintain the state.\nFor this the developer just needs to make extend of the correct base interface. For example, I could declare a Serverless Actor using the following code:\n\n```java\npackage io.eigr.spawn.java.demo.actors;\n\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatelessActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport domain.Reply;\nimport domain.Request;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.action;\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.name;\n\npublic final class StatelessNamedActor implements StatelessActor {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"StatelessNamedActor\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003c?\u003e context, Request msg) {\n        return Value.at()\n                .response(Reply.newBuilder()\n                        .setResponse(String.format(\"Hi %s. Hello From Java\", msg.getLanguage()))\n                        .build())\n                .reply();\n    }\n}\n\n```\n\nOther than that the same Named, UnNamed types are supported. Just use the NamedActorBehavior or UnNamedActorBehavior class inside a `configure` method.\n\n### Considerations about Spawn actors\n\nAnother important feature of Spawn Actors is that the lifecycle of each Actor is managed by the platform itself. \nThis means that an Actor will exist when it is invoked and that it will be deactivated after an idle time in its execution. \nThis pattern is known as [Virtual Actors](#virtual-actors) but Spawn's implementation differs from some other known \nframeworks like [Orleans](https://www.microsoft.com/en-us/research/project/orleans-virtual-actors/) or \n[Dapr](https://docs.dapr.io/developing-applications/building-blocks/actors/actors-overview/) \nby defining a specific behavior depending on the type of Actor (named, unnamed, pooled, and etc...).\n\nFor example, named actors are instantiated the first time as soon as the host application registers them with the Spawn proxy. \nWhereas unnamed and pooled actors are instantiated the first time only when they receive their first invocation call.\n\n### Broadcast\n\nActors in Spawn can subscribe to a thread and receive, as well as broadcast, events for a given thread.\n\nTo consume from a topic, you just need to configure the Actor using the channel option as follows:\n\n```\nreturn new NamedActorBehavior(\n  name(\"JoeActor\"),\n  channel(\"test.channel\"),\n);\n```\nIn the case above, the Actor `JoeActor` was configured to receive events that are forwarded to the topic called `test.channel`.\n\nTo produce events in a topic, just use the Broadcast Workflow. The example below demonstrates a complete example of \nproducing and consuming events. In this case, the same actor is the event consumer and producer, but in a more realistic scenario, \ndifferent actors would be involved in these processes.\n\n```Java\npackage io.eigr.spawn.java.demo.actors;\n\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport io.eigr.spawn.api.actors.workflows.Broadcast;\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class LoopActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"LoopActor\"),\n                channel(\"test.channel\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        return Value.at()\n                .flow(Broadcast.to(\"test.channel\", \"setLanguage\", msg))\n                .response(Reply.newBuilder()\n                        .setResponse(\"Hello From Erlang\")\n                        .build())\n                .state(updateState(\"erlang\"))\n                .reply();\n    }\n\n    // ...\n}\n```\n\n### Side Effects\n\nActors can also emit side effects to other Actors as part of their response.\nSee an example:\n\n```Java\npackage io.eigr.spawn.java.demo.actors;\n\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"JoeActor\"),\n                channel(\"test.channel\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        ActorRef sideEffectReceiverActor = ctx.getSpawnSystem()\n                .createActorRef(ActorIdentity.of(\"spawn-system\", \"MikeFriendActor\", \"MikeParentActor\"));\n\n        return Value.at()\n                .flow(SideEffect.to(sideEffectReceiverActor, \"setLanguage\", msg))\n                .response(Reply.newBuilder()\n                        .setResponse(String.format(\"Hi %s. Hello From Java\", msg.getLanguage()))\n                        .build())\n                .state(updateState(msg.getLanguage()))\n                .noReply();\n    }\n\n    // ....\n}\n```\n\nSide effects such as broadcast are not part of the response flow to the caller. They are request-asynchronous events that \nare emitted after the Actor's state has been saved in memory.\n\n### Forward\n\nActors can route some actions to other actors as part of their response. For example, sometimes you may want another \nActor to be responsible for processing a message that another Actor has received. We call this forwarding, \nand it occurs when we want to forward the input argument of a request that a specific Actor has received to the input of \nan action in another Actor.\n\nSee an example:\n\n```Java\npackage io.eigr.spawn.java.demo.actors;\n\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class RoutingActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"RoutingActor\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        ActorRef forwardedActor = ctx.getSpawnSystem()\n                .createActorRef(ActorIdentity.of(\"spawn-system\", \"MikeFriendActor\", \"MikeActor\"));\n\n        return Value.at()\n                .flow(Forward.to(forwardedActor, \"setLanguage\"))\n                .noReply();\n    }\n}\n```\n\n### Pipe\n\nSimilarly, sometimes we want to chain a request through several processes. For example forwarding an actor's computational \noutput as another actor's input. There is this type of routing we call Pipe, as the name suggests, a pipe forwards what \nwould be the response of the received request to the input of another Action in another Actor.\nIn the end, just like in a Forward, it is the response of the last Actor in the chain of routing to the original caller.\n\nExample:\n\n```Java\npackage io.eigr.spawn.java.demo.actors;\n\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class PipeActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"PipeActor\"),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        ActorRef pipeReceiverActor = ctx.getSpawnSystem()\n                .createActorRef(ActorIdentity.of(\"spawn-system\", \"JoeActor\"));\n\n        return Value.at()\n                .response(Reply.newBuilder()\n                        .setResponse(\"Hello From Java\")\n                        .build())\n                .flow(Pipe.to(pipeReceiverActor, \"someAction\"))\n                .state(updateState(\"java\"))\n                .noReply();\n    }\n\n    // ...\n}\n```\n\nForwards and pipes do not have an upper thread limit other than the request timeout.\n\n### State Management\n\nThe Spawn runtime handles the internal state of your actors. It is he who maintains its state based on the types of actors \nand configurations that you, the developer, have made.\n\nThe persistence of the state of the actors happens through snapshots that follow to [Write Behind Pattern](https://redisson.org/glossary/write-through-and-write-behind-caching.html) \nduring the period in which the Actor is active and [Write Ahead](https://martinfowler.com/articles/patterns-of-distributed-systems/wal.html) \nduring the moment of the Actor's deactivation. \nThat is, data is saved at regular intervals asynchronously while the Actor is active and once synchronously \nwhen the Actor suffers a deactivation, when it is turned off.\n\nThese snapshots happen from time to time. And this time is configurable through the ***snapshotTimeout*** method of \nthe ***NamedActorBehavior*** or ***UnNamedActorBehavior*** class. \nHowever, you can tell the Spawn runtime that you want it to persist the data immediately synchronously after executing an Action.\nAnd this can be done in the following way:\n\nExample:\n\n```Java\npackage io.eigr.spawn.test.actors;\n\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.NamedActorBehavior;\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class JoeActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new NamedActorBehavior(\n                name(\"JoeActor\"),\n                snapshot(1000),\n                deactivated(60000),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        return Value.at()\n                .response(Reply.newBuilder()\n                        .setResponse(String.format(\"Hi %s. Hello From Java\", msg.getLanguage()))\n                        .build())\n                .state(updateState(msg.getLanguage()), true)\n                .reply();\n    }\n\n    // ...\n}\n```\n\nThe most important thing in this example is the use of the last parameter with the true value:\n\n```\nstate(updateState(\"java\"), true)\n```\n\nIt is this parameter that will indicate to the Spawn runtime that you want the data to be saved immediately after this \nAction is called back.\nIn most cases this strategy is completely unnecessary, as the default strategy is sufficient for most use cases. \nBut Spawn democratically lets you choose when you want your data persisted.\n\nIn addition to this functionality regarding state management, Spawn also allows you to perform some more operations \non your Actors such as restoring the actor's state to a specific point in time:\n\nRestore Example:\n\nTODO\n\n## Using Actors\n\nThere are several ways to interact with our actors, some internal to the application code and others external to the application code. \nIn this section we will deal with the internal ways of interacting with our actors and this will be done through direct calls to them. \nFor more details on the external ways to interact with your actors see the [Activators](#activators) section.\n\nIn order to be able to call methods of an Actor, we first need to get a reference to the actor. This is done with the \nhelp of the static method `createAactorRef` of the `Spawn` class.\n\nIn the sections below we will give some examples of how to invoke different types of actors in different ways.\n\n### Call Named Actors\n\nTo invoke an actor named like the one we defined in section [Getting Started](#getting-started) we could do as follows:\n\n```Java\nActorRef joeActor = spawnSystem.createActorRef(ActorIdentity.of(\"spawn-system\", \"JoeActor\"));\n        \nRequest msg = Request.newBuilder()\n       .setLanguage(\"erlang\")\n       .build();\n        \nOptional\u003cReply\u003e maybeResponse = joeActor.invoke(\"setLanguage\", msg, Reply.class);\nReply reply = maybeResponse.get();\n```\n\nMore detailed in complete main class:\n\n```java\npackage io.eigr.spawn.java.demo;\n\nimport io.eigr.spawn.api.Spawn;\nimport io.eigr.spawn.api.Spawn.SpawnSystem;\nimport io.eigr.spawn.api.ActorIdentity;\nimport io.eigr.spawn.api.ActorRef;\nimport io.eigr.spawn.api.TransportOpts;\nimport io.eigr.spawn.api.exceptions.SpawnException;\nimport domain.Reply;\nimport domain.Request;\n\npublic class App {\n   public static void main(String[] args) throws SpawnException {\n      Spawn spawnSystem = new SpawnSystem()\n              .create(\"spawn-system\")\n              .withActor(Joe.class)\n              .withTransportOptions(\n                      TransportOpts.builder()\n                              .port(8091)\n                              .proxyPort(9003)\n                              .build()\n              )\n              .build();\n\n      spawnSystem.start();\n\n      ActorRef joeActor = spawnSystem.createActorRef(ActorIdentity.of(\"spawn-system\", \"JoeActor\"));\n\n      Request msg = Request.newBuilder()\n              .setLanguage(\"erlang\")\n              .build();\n     \n      joeActor.invoke(\"setLanguage\", msg, Reply.class)\n              .ifPresent(response -\u003e  log.info(\"Response is: {}\", response));\n   }\n}\n```\n\n### Call Unnamed Actors\n\nUnnamed actors are equally simple to invoke. All that is needed is to inform the `parent` parameter which refers to the \nname given to the actor that defines the ActorRef template.\n\nTo better exemplify, let's first show the Actor's definition code and later how we would call this actor with a concrete \nname at runtime:\n\n```java\npackage io.eigr.spawn.test.actors;\n\nimport io.eigr.spawn.api.actors.ActionBindings;\nimport io.eigr.spawn.api.actors.ActorContext;\nimport io.eigr.spawn.api.actors.StatefulActor;\nimport io.eigr.spawn.api.actors.Value;\nimport io.eigr.spawn.api.actors.behaviors.ActorBehavior;\nimport io.eigr.spawn.api.actors.behaviors.BehaviorCtx;\nimport io.eigr.spawn.api.actors.behaviors.UnNamedActorBehavior;\nimport domain.Reply;\nimport domain.Request;\nimport domain.State;\n\nimport static io.eigr.spawn.api.actors.behaviors.ActorBehavior.*;\n\npublic final class MikeActor implements StatefulActor\u003cState\u003e {\n\n    @Override\n    public ActorBehavior configure(BehaviorCtx context) {\n        return new UnNamedActorBehavior(\n                name(\"MikeActor\"),\n                snapshot(1000),\n                deactivated(60000),\n                action(\"SetLanguage\", ActionBindings.of(Request.class, this::setLanguage))\n        );\n    }\n\n    private Value setLanguage(ActorContext\u003cState\u003e context, Request msg) {\n        return Value.at()\n                .response(Reply.newBuilder()\n                        .setResponse(String.format(\"Hi %s. Hello From Java\", msg.getLanguage()))\n                        .build())\n                .state(updateState(msg.getLanguage()), true)\n                .reply();\n    }\n\n    // ...\n}\n```\n\nSo you could define and call this actor at runtime like this:\n\n```Java\nActorRef mike = spawnSystem.createActorRef(ActorIdentity.of(\"spawn-system\", \"MikeInstanceActor\", \"MikeActor\"));\n        \nRequest msg = Request.newBuilder()\n       .setLanguage(\"erlang\")\n       .build();\n\nOptional\u003cReply\u003e maybeResponse = mike.invoke(\"setLanguage\", msg, Reply.class);\nReply reply = maybeResponse.get();\n```\n\nThe important part of the code above is the following snippet:\n\n```Java\nActorRef mike = spawnSystem.createActorRef(ActorIdentity.of(\"spawn-system\", \"MikeInstanceActor\", \"MikeActor\"));\n```\n\nThese tells Spawn that this actor will actually be named at runtime. The name parameter with value \"MikeInstanceActor\" \nin this case is just a reference to \"MikeActor\" Actor that will be used later \nso that we can actually create an instance of the real Actor.\n\n### Async\n\nBasically Spawn can perform actor functions in two ways. Synchronously, where the callee waits for a response, \nor asynchronously, where the callee doesn't care about the return value of the call. \nIn this context we should not confuse Spawn's asynchronous way with Java's concept of async like Promises because async for Spawn is \njust a fire-and-forget call.\n\nTherefore, to call an actor's function asynchronously, just use the invokeAsync method:\n\n```Java\nmike.invokeAsync(\"setLanguage\", msg);\n```\n\n### Timeouts\n\nIt is possible to change the request waiting timeout using the invocation options as below:\n\n```Java\npackage io.eigr.spawn.java.demo;\n\n// omitted imports for brevity\n\npublic class App {\n   public static void main(String[] args) {\n      Spawn spawnSystem = new Spawn.SpawnSystem()\n              .create(\"spawn-system\")\n              .withActor(Joe.class)\n              .build();\n\n      spawnSystem.start();\n\n      ActorRef joeActor = spawnSystem.createActorRef(ActorIdentity.of(\"spawn-system\", \"JoeActor\"));\n\n      Request msg = Request.newBuilder()\n              .setLanguage(\"erlang\")\n              .build();\n\n      InvocationOpts opts = InvocationOpts.builder()\n              .timeoutSeconds(Duration.ofSeconds(30))\n              .build();\n      \n      Optional\u003cReply\u003e maybeResponse = joeActor.invoke(\"setLanguage\", msg, Reply.class, opts);\n   }\n}\n```\n\n## Deploy\n\nSee [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more \ndetails on how to deploy a Spawn application.\n\n### Defining an ActorSystem\n\nSee [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more \ndetails on how to define an ActorSystem.\n\n### Defining an ActorHost\n\nSee [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more \ndetails on how to define an ActorHost.\n\n### Activators\nTODO\n\n## Actor Model\n\nAccording to Wikipedia Actor Model is:\n\n\"A mathematical model of concurrent computation that treats actor as the universal primitive of concurrent computation. \nIn response to a message it receives, an actor can: make local decisions, create more actors, send more messages, \nand determine how to respond to the next message received. Actors may modify their own private state, but can only affect \neach other indirectly through messaging (removing the need for lock-based synchronization).\n\nThe actor model originated in 1973. It has been used both as a framework for a theoretical understanding of computation \nand as the theoretical basis for several practical implementations of concurrent systems.\"\n\nThe Actor Model was proposed by Carl Hewitt, Peter Bishop, and Richard Steiger and is inspired by several characteristics of the physical world.\n\nAlthough it emerged in the 70s of the last century, only in the previous two decades of our century has this model \ngained strength in the software engineering communities due to the massive amount of existing data and the performance \nand distribution requirements of the most current applications.\n\nFor more information about the Actor Model, see the following links:\n\nhttps://en.wikipedia.org/wiki/Actor_model\n\nhttps://codesync.global/media/almost-actors-comparing-pony-language-to-beam-languages-erlang-elixir/\n\nhttps://www.infoworld.com/article/2077999/understanding-actor-concurrency--part-1--actors-in-erlang.html\n\nhttps://doc.akka.io/docs/akka/current/general/actors.html\n\n### Virtual Actors\n\nIn the context of the Virtual Actor paradigm, actors possess the inherent ability to seamlessly retain their state. \nThe underlying framework dynamically manages the allocation of actors to specific nodes. If a node happens to experience an outage, \nthe framework automatically revives the affected actor on an alternate node. This process of revival maintains \ndata integrity as actors are inherently designed to preserve their state. Interruptions to availability are minimized \nduring this seamless transition, contingent on the actors correctly implementing their state preservation mechanisms.\n\nThe Virtual Actor model offers several merits:\n\n* **Scalability**: The system can effortlessly accommodate a higher number of actor instances by introducing additional nodes.\n\n* **Availability**: In case of a node failure, actors swiftly and nearly instantly regenerate on another node, \nall while safeguarding their state from loss.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feigr%2Fspawn-java-std-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feigr%2Fspawn-java-std-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feigr%2Fspawn-java-std-sdk/lists"}