{"id":21625401,"url":"https://github.com/eigr/spawn-python-sdk","last_synced_at":"2025-04-11T12:35:15.469Z","repository":{"id":48409636,"uuid":"516889488","full_name":"eigr/spawn-python-sdk","owner":"eigr","description":"Spawn Actor Service Mesh Python Support","archived":false,"fork":false,"pushed_at":"2023-08-29T21:00:02.000Z","size":252,"stargazers_count":9,"open_issues_count":4,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-07T18:02:17.210Z","etag":null,"topics":["actor-model","cloud-computing","domain-driven-design","event-driven","serverless","state-management","stateful-actors","virtual-actors"],"latest_commit_sha":null,"homepage":"https://eigr.io","language":"Python","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":null,"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}},"created_at":"2022-07-22T21:19:40.000Z","updated_at":"2024-02-01T17:48:13.000Z","dependencies_parsed_at":"2023-01-24T01:45:46.395Z","dependency_job_id":null,"html_url":"https://github.com/eigr/spawn-python-sdk","commit_stats":null,"previous_names":["eigr/spawn-python-sdk"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-python-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-python-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-python-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eigr%2Fspawn-python-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eigr","download_url":"https://codeload.github.com/eigr/spawn-python-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248402324,"owners_count":21097328,"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":["actor-model","cloud-computing","domain-driven-design","event-driven","serverless","state-management","stateful-actors","virtual-actors"],"created_at":"2024-11-25T01:09:06.077Z","updated_at":"2025-04-11T12:35:15.445Z","avatar_url":"https://github.com/eigr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spawn Python SDK\nPython User Language Support for [Spawn](https://github.com/eigr/spawn).\n\n# Table of Contents\n\n1. [Overview](#overview)\n2. [Getting Started](#getting-started)\n3. [Advanced Use Cases](#advanced-use-cases)\n   - [Types of Actors](#types-of-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 and other options](#async-calls-and-other-options)\n5. [Deploy](#deploy)\n   - [Packing with Containers](#packing-with-containers)\n   - [Defining an ActorSytem](#defining-an-actorsytem)\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 basead 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, as 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 infrastructure 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) and [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 must create a new Python project. In this example we will use [Poetry](https://python-poetry.org) as our package manager.\n\n```shell\npoetry new spawn-py-demo\n```\n\nThe second thing we have to do is add the spawn dependency to the project.\n\n```toml\n[tool.poetry.dependencies]\npython = \"\u003e=3.9.7,\u003c4.0\"\nspawn = {git = \"https://github.com/eigr/spawn-python-sdk.git\"}\n```\n\nNow it is necessary to download the dependencies via Poetry:\n\n```shell\npoetry env use python3 # use your own python here\npoetry lock\npoetry 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. In the root of the project we will create a folder called protobuf and some subfolders\n\n```shell\nmkdir -p spawn_py_demo/protobuf/domain\n```\n\nThat done, let's create our protobuf file inside the example folder.\n\n```shell\ntouch spawn_py_demo/protobuf/domain/domain.proto\n```\n\nAnd let's populate this file with the following content:\n\n```proto\nsyntax = \"proto3\";\n\npackage domain;\n\nmessage JoeState {\n  repeated string languages = 1;\n}\n\nmessage Request {\n  string language = 1;\n}\n\nmessage Reply {\n  string response = 1;\n}\n```\n\nWe must compile this file using the protoc utility. In the root of the project type the following command:\n\n```shell\nprotoc -I spawn_py_demo/protobuf/ --python_out=spawn_py_demo spawn_py_demo/protobuf/domain/domain.proto\n```\n\nNow in the spawn_py_demo folder we will create our first python file containing the code of our Actor.\n\n```shell\ntouch spawn_py_demo/joe.py\n```\n\nPopulate this file with the following content:\n\n```python\nfrom domain.domain_pb2 import JoeState\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\n\nactor = Actor(settings=ActorSettings(\n    name=\"joe\", stateful=True, channel=\"test\"))\n\n\n@actor.timer_action(every=1000)\ndef hi(ctx: Context) -\u003e Value:\n    new_state = None\n\n    if not ctx.state:\n        new_state = JoeState()\n        new_state.languages.append(\"python\")\n    else:\n        new_state = ctx.state\n\n    return Value().state(new_state).noreply()\n```\n\nNow with our Actor properly defined, we just need to start the SDK correctly. Create another file called main.py to serve as your application's entrypoint and fill it with the following content:\n\n```python\nfrom spawn.eigr.functions.actors.api.sdk import Spawn\nfrom joe import actor as joe_actor\n\nif __name__ == \"__main__\":\n    spawn = Spawn()\n    spawn.port(8091).proxy_port(9003).actor_system(\n        \"spawn-system\").add_actor(joe_actor).start()\n```\n\nThen:\n\n```shell\npoetry run python3 spawn_py_demo/main.py\n```\n\nBut of course you will need to locally run the our Elixir proxy which will actually provide all the functionality for your Python application. One way to do this is to create a docker-compose file containing all the services that your application depends on, in this case, in addition to the Spawn proxy, it also has a database and possibly a nats broker if you want access to more advanced Spawn features.\n\n```docker-compose\nversion: \"3.8\"\nservices:\n  mariadb:\n    image: mariadb\n    environment:\n      MYSQL_ROOT_PASSWORD: admin\n      MYSQL_DATABASE: eigr-functions-db\n      MYSQL_USER: admin\n      MYSQL_PASSWORD: admin\n    volumes:\n      - mariadb:/var/lib/mysql\n    ports:\n      - \"3307:3306\"\n  nats:\n    image: nats:0.8.0\n    entrypoint: \"/gnatsd -DV\"\n    ports:\n      - \"8222:8222\"\n      - \"4222:4222\"\n  spawn-proxy:\n    build:\n      context: https://github.com/eigr/spawn.git#main\n      dockerfile: ./Dockerfile-proxy\n    restart: always\n    network_mode: \"host\"\n    environment:\n      SPAWN_USE_INTERNAL_NATS: \"true\"\n      SPAWN_PUBSUB_ADAPTER: nats\n      SPAWN_STATESTORE_KEY: 3Jnb0hZiHIzHTOih7t2cTEPEpY98Tu1wvQkPfq/XwqE=\n      PROXY_APP_NAME: spawn\n      PROXY_CLUSTER_STRATEGY: gossip\n      PROXY_DATABASE_PORT: 3307\n      PROXY_DATABASE_TYPE: mariadb\n      PROXY_HTTP_PORT: 9003\n      USER_FUNCTION_PORT: 8091\n    depends_on:\n      - mariadb\n      - nats\nnetworks:\n  mysql-compose-network:\n    driver: bridge\nvolumes:\n  mariadb:\n\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## Advanced Use Cases\n\nSpawn Actors abstract a huge amount of developer infrastructure and can be used for many different types of jobs. In the sections below we will demonstrate some of the features available in Spawn that contribute to the development of complex applications in a simplified way.\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 than unnamed actors and pooled actors. Named actors when they are defined with the stateful parameter equal to True are immediately instantiated when they are registered at the beginning of the program, they can also only be referenced by the 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, during 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 assigned to them at compile time. Pooled actors are generally used when higher performance is needed and are also recommended for handling serverless loads.\n\nAnother important feature of Spawn Actors is that the lifecycle of each Actor is managed by the platform itself. This means that an Actor will exist when it is invoked and that it will be deactivated after an idle time in its execution. This pattern is known as [Virtual Actors](#virtual-actors) but Spawn's implementation differs from some other known frameworks like [Orleans](https://www.microsoft.com/en-us/research/project/orleans-virtual-actors/) or [Dapr](https://docs.dapr.io/developing-applications/building-blocks/actors/actors-overview/) by 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. Whereas 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 decorator using the channel option as follows:\n\n```python\nactor = Actor(settings=ActorSettings(\n    name=\"joe\", stateful=True, channel=\"test\"))\n```\nIn the case above, the Actor `joe` was configured to receive events that are forwarded to the topic called `test`.\n\nTo produce events in a topic, just use the Broadcast Workflow. The example below demonstrates a complete example of producing and consuming events. In this case, the same actor is the event consumer and producer, but in a more realistic scenario, different actors would be involved in these processes.\n\n```python\nfrom domain.domain_pb2 import JoeState, Request, Reply\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\nfrom spawn.eigr.functions.actors.api.workflows.broadcast import Broadcast\n\nactor = Actor(settings=ActorSettings(\n    name=\"joe\", stateful=True, channel=\"test\"))\n\n\n@actor.timer_action(every=1000)\ndef hi(ctx: Context) -\u003e Value:\n    new_state = None\n    request = Request()\n    request.language = \"python\"\n    broadcast = Broadcast()\n    broadcast.channel = \"test\"\n    broadcast.action_name = \"setLanguage\"\n    broadcast.value = request\n\n    if not ctx.state:\n        new_state = JoeState()\n        new_state.languages.append(\"python\")\n    else:\n        new_state = ctx.state\n\n    return Value()\\\n        .broadcast(broadcast)\\\n        .state(new_state)\\\n        .noreply()\n\n\n@actor.action(\"setLanguage\")\ndef set_language(request: Request, ctx: Context) -\u003e Value:\n    reply = Reply()\n    reply.response = \"erlang\"\n    return Value().of(reply, ctx.state).reply()\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```python\nfrom domain.domain_pb2 import State, Request, Reply\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\nfrom spawn.eigr.functions.actors.api.workflows.effect import Effect\n\n\nactor = Actor(settings=ActorSettings(name=\"joe\", stateful=True))\n\n\n@actor.timer_action(every=1000)\ndef hi(ctx: Context) -\u003e Value:\n    new_state = None\n    request = Request()\n    request.language = \"python\"\n\n    effect: Effect = Effect(action=\"setLanguage\", payload=request,\n                            system=\"spawn-system\", actor=\"mike\", parent=\"abs_actor\")\n\n    if not ctx.state:\n        new_state = State()\n        new_state.languages.append(\"python\")\n    else:\n        new_state = ctx.state\n\n    return Value()\\\n        .effect(effect)\\\n        .state(new_state)\\\n        .noreply()\n\n```\n\nSide effects such as broadcast are not part of the response flow to the caller. They are request-asynchronous events that are 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 Actor to be responsible for processing a message that another Actor has received. We call this forwarding and it occurs when we want to forward the input argument of a request that a specific Actor has received to the input of an action in another Actor.\n\nSee an example:\n\n```python\nfrom domain.domain_pb2 import Request\n\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\nfrom spawn.eigr.functions.actors.api.workflows.forward import Forward\n\nactor = Actor(settings=ActorSettings(name=\"joe\", stateful=True))\n\n@actor.action(\"setLanguage\")\ndef set_language(request: Request, ctx: Context) -\u003e Value:\n    return Value()\\\n        .forward(Forward(\"mike\", \"setLanguage\"))\\\n        .reply()\n```\n\n### Pipe\n\nSimilarly, sometimes we want to chain a request through several different processes. For example forwarding an actor's computational output as another actor's input. There is this type of routing we call Pipe, as the name suggests, a pipe forwards what would 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```python\nfrom domain.domain_pb2 import State, Request, Reply\n\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\nfrom spawn.eigr.functions.actors.api.workflows.pipe import Pipe\n\nactor = Actor(settings=ActorSettings(name=\"joe\", stateful=True))\n\n@actor.action(\"setLanguage\")\ndef set_language(request: Request, ctx: Context) -\u003e Value:\n    reply = Reply()\n    reply.language = \"python\"\n\n    if not ctx.state:\n        new_state = State()\n        new_state.languages.append(\"python\")\n    else:\n        new_state = ctx.state\n\n    return Value()\\\n        .response(reply)\\\n        .pipe(Pipe(\"mike\", \"setLanguage\"))\\\n        .reply()\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 and configurations that you, the developer, have made.\n\nThe persistence of the state of the actors happens through snapshots that follow the [Write Behind Pattern](https://redisson.org/glossary/write-through-and-write-behind-caching.html) during the period in which the Actor is active and [Write Ahead](https://martinfowler.com/articles/patterns-of-distributed-systems/wal.html) during the moment of the Actor's deactivation. That is, data is saved at regular intervals asynchronously while the Actor is active and once synchronously when 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 ***snapshot_timeout*** property of the ***ActorSettings*** class. However, you can tell the Spawn runtime that you want it to persist the data immediately synchronously after executing an Action. And this can be done in the following way:\n\nExample:\n\n```python\nfrom domain.domain_pb2 import State, Request, Reply\n\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\nfrom spawn.eigr.functions.actors.api.workflows.pipe import Pipe\n\nactor = Actor(settings=ActorSettings(name=\"joe\", stateful=True, snapshot_timeout=2000))\n\n@actor.action(\"setLanguage\")\ndef set_language(request: Request, ctx: Context) -\u003e Value:\n    reply = Reply()\n    reply.language = \"python\"\n\n    if not ctx.state:\n        new_state = State()\n        new_state.languages.append(\"python\")\n    else:\n        new_state = ctx.state\n\n    return Value()\\\n        .response(reply)\\\n        .pipe(Pipe(\"mike\", \"setLanguage\"))\\\n        .reply(checkpoint=True)\n```\n\nThe most important thing in this example is the use of the parameter checkpoint=True:\n\n```python\n.reply(checkpoint=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 Action is called back.\nIn most cases this strategy is completely unnecessary, as the default strategy is sufficient for most use cases. But 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 on 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. In this section we will deal with the internal ways of interacting with our actors and this will be done through direct calls to them. For 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 help of the static method `create_actor_ref` of the `Spawn` class. This method accepts some arguments, the most important being `system`, `actor_name` and `parent`. \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```python\nactor: ActorRef = Spawn.create_actor_ref(\n    system=\"spawn-system\",\n    actor_name=\"joe\"\n)\n\nrequest = Request()\nrequest.language = \"erlang\"\n\n(status, result) = actor.invoke(\n    action=\"setLanguage\", request=request)\nprint(\"Invocation Result Status: \" + status)\nprint(\"Invocation Result Value:  \" + str(result.response))\n```\n\nCalls like the one above, that is, synchronous calls, always returned a tuple composed of the invocation status message and the response object emitted by the Actor.\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 name 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 name at runtime:\n\n```python\nfrom domain.domain_pb2 import State, Request, Reply\nfrom spawn.eigr.functions.actors.api.actor import Actor\nfrom spawn.eigr.functions.actors.api.settings import ActorSettings, Kind\nfrom spawn.eigr.functions.actors.api.context import Context\nfrom spawn.eigr.functions.actors.api.value import Value\n\nabstract = Actor(settings=ActorSettings(\n    name=\"abs_actor\", stateful=True, kind=Kind.UNNAMED))\n\n\n@abstract.action(\"setLanguage\")\ndef set_language(request: Request, ctx: Context) -\u003e Value:\n    print(\"Request -\u003e \" + str(request))\n    print(\"Current State -\u003e \" + str(ctx.state))\n\n    reply = Reply()\n    reply.response = \"erlang\"\n    new_state = State()\n    new_state.languages.append(\"python\")\n    return Value().of(reply, new_state).reply()\n```\n\nThe important part of the code above is the following snippet:\n\n```python\nabstract = Actor(settings=ActorSettings(\n    name=\"abs_actor\", stateful=True, kind=Kind.UNNAMED))\n```\n\nThis tells Spawn that this actor will actually be named at runtime. The name parameter in this case is just a reference that will be used later so that we can actually create an instance of the real Actor.\n\nFinally below we will see how to invoke such an actor. We'll name the royal actor \"mike\":\n\n```python\n# Get abstract actor reference called mike\nactor: ActorRef = Spawn.create_actor_ref(\n    system=\"spawn-system\",\n    actor_name=\"mike\",\n    parent=\"abs_actor\"\n)\n\nrequest = Request()\nrequest.language = \"erlang\"\n\n(status, result) = actor.invoke(\n    action=\"setLanguage\", request=request)\nprint(\"Invocation Result Status: \" + status)\nprint(\"Invocation Result Value:  \" + str(result.response))\n```\n\n### Async calls and other options\n\nBasically Spawn can perform actor functions in two ways. Synchronously, where the callee waits for a response, or asynchronously, where the callee doesn't care about the return value of the call. In this context we should not confuse Spawn's asynchronous way with Python's concept of async because async for Spawn is just a fire-and-forget call.\n\nTherefore, to call an actor's function asynchronously, just inform the parameter async_mode with the value True:\n\n```python\nsome_actor.invoke(\n    action=\"setLanguage\", request=request, async_mode=True)\n```\n\n## Deploy\n\nSee [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more details on how to deploy a Spawn application.\n\n### Packing with Containers \n\nSpawn is a k8s based runtime and therefore your workloads should be made up of containers.\n\nSo all you need to do is create a container with your Python application. There are several tutorials on the internet that can help you with this process and we will not go into detail in this document.\n\n### Defining an ActorSytem\n\nSee [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more details 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 details 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. In response to a message it receives, an actor can: make local decisions, create more actors, send more messages, and determine how to respond to the next message received. Actors may modify their own private state, but can only affect each 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 and 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 gained strength in the software engineering communities due to the massive amount of existing data and the performance and 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. The underlying framework dynamically manages the allocation of actors to specific nodes. If a node happens to experience an outage, the framework automatically revives the affected actor on an alternate node. This process of revival maintains data integrity as actors are inherently designed to preserve their state. Interruptions to availability are minimized during 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, all while safeguarding their state from loss.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feigr%2Fspawn-python-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feigr%2Fspawn-python-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feigr%2Fspawn-python-sdk/lists"}