{"id":27706157,"url":"https://github.com/AsynkronIT/protoactor-go","last_synced_at":"2025-04-26T05:01:54.607Z","repository":{"id":36977275,"uuid":"56453473","full_name":"asynkron/protoactor-go","owner":"asynkron","description":"Proto Actor - Ultra fast distributed actors for Go, C# and Java/Kotlin","archived":false,"fork":false,"pushed_at":"2024-08-22T20:23:45.000Z","size":37143,"stargazers_count":5193,"open_issues_count":85,"forks_count":535,"subscribers_count":201,"default_branch":"dev","last_synced_at":"2025-04-18T20:14:04.115Z","etag":null,"topics":["actor-model","actors","akka","clustering","cross-platform","distributed-computing","distributed-systems","go","golang","grpc","protobuf"],"latest_commit_sha":null,"homepage":"http://proto.actor","language":"Go","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/asynkron.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","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},"funding":{"github":["rogeralsing"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2016-04-17T19:08:14.000Z","updated_at":"2025-04-17T16:55:20.000Z","dependencies_parsed_at":"2024-03-22T09:47:36.168Z","dependency_job_id":"da1a75da-d2dc-416b-9ad4-59e790c505c6","html_url":"https://github.com/asynkron/protoactor-go","commit_stats":{"total_commits":2022,"total_committers":105,"mean_commits":"19.257142857142856","dds":"0.47131552917903063","last_synced_commit":"3c0e61ca19c98427692686c5367893050d41e9bf"},"previous_names":["rogeralsing/gam","asynkronit/protoactor-go","asynkronit/protoactor","asynkronit/gam"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynkron%2Fprotoactor-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynkron%2Fprotoactor-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynkron%2Fprotoactor-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynkron%2Fprotoactor-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asynkron","download_url":"https://codeload.github.com/asynkron/protoactor-go/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250935455,"owners_count":21510552,"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","actors","akka","clustering","cross-platform","distributed-computing","distributed-systems","go","golang","grpc","protobuf"],"created_at":"2025-04-26T05:01:27.085Z","updated_at":"2025-04-26T05:01:54.565Z","avatar_url":"https://github.com/asynkron.png","language":"Go","funding_links":["https://github.com/sponsors/rogeralsing"],"categories":["Go"],"sub_categories":[],"readme":"[![Go Report Card](https://goreportcard.com/badge/github.com/asynkron/protoactor-go)](https://goreportcard.com/report/github.com/asynkron/protoactor-go)\n[![GoDoc](https://godoc.org/github.com/asynkron/protoactor-go?status.svg)](https://godoc.org/github.com/asynkron/protoactor-go)\n[![checks](https://github.com/asynkron/protoactor-go/actions/workflows/checks.yml/badge.svg)](https://github.com/asynkron/protoactor-go/actions/workflows/checks.yml)\n[![Sourcegraph](https://sourcegraph.com/github.com/asynkron/protoactor-go/-/badge.svg)](https://sourcegraph.com/github.com/asynkron/protoactor-go?badge)\n\n### [Join our Slack channel](https://join.slack.com/t/asynkron/shared_invite/zt-ko824601-yGN1d3GHF9jzZX2VtONodQ)\n\n# Cross platform actors\n\nIntroducing cross platform actor support between Go and C#.\n\nCan I use this?\nThe Go implementation is still in beta, there are users using Proto Actor for Go in production already.\nBut be aware that the API might change over time until 1.0.\n\n## Sourcecode - Go\n\nThis is the Go repository for Proto Actor.\n\nThe C# implementation can be found\nhere [https://github.com/asynkron/protoactor-dotnet](https://github.com/asynkron/protoactor-dotnet)\n\n## Design principles:\n\n**Minimalistic API** -\nThe API should be small and easy to use.\nAvoid enterprisey JVM like containers and configurations.\n\n**Build on existing technologies** - There are already a lot of great tech for e.g. networking and clustering, build on\nthose.\ne.g. gRPC streams for networking, Consul.IO for clustering.\n\n**Pass data, not objects** - Serialization is an explicit concern, don't try to hide it.\nProtobuf all the way.\n\n**Be fast** - Do not trade performance for magic API trickery.\n\nUltra fast remoting, Proto Actor currently manages to pass over **two million messages per second** between nodes using\nonly two actors, while still preserving message order!\nThis is six times more the new super advanced UDP based Artery transport for Scala Akka, and 30 times faster than\nAkka.NET.\n\n```text\n:\u003e node1.exe\nStarted EndpointManager\nStarted Activator\nStarting Proto.Actor server address=\"127.0.0.1:8081\"\nStarted EndpointWatcher address=\"127.0.0.1:8080\"\nStarted EndpointWriter address=\"127.0.0.1:8080\"\nEndpointWriter connecting address=\"127.0.0.1:8080\"\nEndpointWriter connected address=\"127.0.0.1:8080\"\n2020/06/22 10:45:20 Starting to send\n2020/06/22 10:45:20 50000\n2020/06/22 10:45:20 100000\n2020/06/22 10:45:20 150000\n... snip ...\n2020/06/22 10:45:21 900000\n2020/06/22 10:45:21 950000\n2020/06/22 10:45:21 1000000\n2020/06/22 10:45:21 Elapsed 732.9921ms\n2020/06/22 10:45:21 Msg per sec 2728542 \u003c--\n\n```\n\n## History\n\nAs the creator of the Akka.NET project, I have come to some distinct conclusions while being involved in that project.\nIn Akka.NET we created our own thread pool, our own networking layer, our own serialization support, our own\nconfiguration support etc. etc.\nThis was all fun and challenging, it is however now my firm opinion that this is the wrong way to go about things.\n\n**If possible, software should be composed, not built**, only add code to glue existing pieces together.\nThis yields a much better time to market, and allows us to focus on solving the actual problem at hand, in this case\nconcurrency and distributed programming.\n\nProto Actor builds on existing technologies, Protobuf for serialization, gRPC streams for network transport.\nThis ensures cross platform compatibility, network protocol version tolerance and battle proven stability.\n\nAnother extremely important factor here is business agility and having an exit strategy.\nBy being cross platform, your organization is no longer tied into a specific platform, if you are migrating from .NET to\nGo,\nThis can be done while still allowing actor based services to communicate between platforms.\n\nReinvent by not reinventing.\n\n---\n\n## Why Actors\n\n![batman](/resources/batman.jpg)\n\n- Decoupled Concurrency\n- Distributed by default\n- Fault tolerance\n\nFor a more indepth description of the differences, see this\nthread [Actors vs. CSP](https://www.quora.com/Go-programming-language-How-are-Akka-actors-are-different-than-Goroutines-and-Channels)\n\n## Building\n\nYou need to ensure that your `$GOPATH` variable is properly set.\n\nNext, install the [standard protocol buffer implementation](https://github.com/google/protobuf) and run the following\ncommands to get all the necessary tooling:\n\n```\ngo get github.com/asynkron/protoactor-go/...\ncd $GOPATH/src/github.com/asynkron/protoactor-go\ngo get ./...\nmake\n```\n\nAfter invoking last command you will have generated protobuf definitions and built the project.\n\nWindows users can use Cygwin to run make: [www.cygwin.com](https://www.cygwin.com/)\n\n## Testing\n\nThis command exectutes all tests in the repository except for consul integration tests (you need consul for running\nthose tests). We also skip directories that don't contain any tests.\n\n```\ngo test `go list ./... | grep -v \"/examples/\" | grep -v \"/persistence\" | grep -v \"/scheduler\"`\n```\n## Hello world\n\n```go\ntype Hello struct{ Who string }\ntype HelloActor struct{}\n\nfunc (state *HelloActor) Receive(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case Hello:\n        fmt.Printf(\"Hello %v\\n\", msg.Who)\n    }\n}\n\nfunc main() {\n    context := actor.EmptyRootContext\n    props := actor.PropsFromProducer(func() actor.Actor { return \u0026HelloActor{} })\n    pid, err := context.Spawn(props)\n    if err != nil {\n        panic(err)\n    }\n    context.Send(pid, Hello{Who: \"Roger\"})\n    console.ReadLine()\n}\n```\n\n## State machines / SetBehavior, PushBehavior and PopBehavior\n\n```go\ntype Hello struct{ Who string }\ntype SetBehaviorActor struct{}\n\nfunc (state *SetBehaviorActor) Receive(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case Hello:\n        fmt.Printf(\"Hello %v\\n\", msg.Who)\n        context.SetBehavior(state.Other)\n    }\n}\n\nfunc (state *SetBehaviorActor) Other(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case Hello:\n        fmt.Printf(\"%v, ey we are now handling messages in another behavior\", msg.Who)\n    }\n}\n\nfunc NewSetBehaviorActor() actor.Actor {\n    return \u0026SetBehaviorActor{}\n}\n\nfunc main() {\n    context := actor.EmptyRootContext\n    props := actor.PropsFromProducer(NewSetBehaviorActor)\n    pid, err := context.Spawn(props)\n    if err != nil {\n        panic(err)\n    }\n    context.Send(pid, Hello{Who: \"Roger\"})\n    context.Send(pid, Hello{Who: \"Roger\"})\n    console.ReadLine()\n}\n```\n\n## Lifecycle events\n\nUnlike Akka, Proto Actor uses messages for lifecycle events instead of OOP method overrides\n\n```go\ntype Hello struct{ Who string }\ntype HelloActor struct{}\n\nfunc (state *HelloActor) Receive(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case *actor.Started:\n        fmt.Println(\"Started, initialize actor here\")\n    case *actor.Stopping:\n        fmt.Println(\"Stopping, actor is about shut down\")\n    case *actor.Stopped:\n        fmt.Println(\"Stopped, actor and its children are stopped\")\n    case *actor.Restarting:\n        fmt.Println(\"Restarting, actor is about restart\")\n    case Hello:\n        fmt.Printf(\"Hello %v\\n\", msg.Who)\n    }\n}\n\nfunc main() {\n    context := actor.EmptyRootContext\n    props := actor.PropsFromProducer(func() actor.Actor { return \u0026HelloActor{} })\n    pid, err := context.Spawn(props)\n    if err != nil {\n        panic(err)\n    }\n    context.Send(pid, Hello{Who: \"Roger\"})\n\n    // why wait?\n    // Stop is a system message and is not processed through the user message mailbox\n    // thus, it will be handled _before_ any user message\n    // we only do this to show the correct order of events in the console\n    time.Sleep(1 * time.Second)\n    context.Stop(pid)\n\n    console.ReadLine()\n}\n```\n\n## Supervision\n\nRoot actors are supervised by the `actor.DefaultSupervisionStrategy()`, which always issues a `actor.RestartDirective`\nfor failing actors\nChild actors are supervised by their parents.\nParents can customize their child supervisor strategy using `Proto Actor.Props`\n\n### Example\n\n```go\ntype Hello struct{ Who string }\ntype ParentActor struct{}\n\nfunc (state *ParentActor) Receive(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case Hello:\n        props := actor.PropsFromProducer(NewChildActor)\n        child := context.Spawn(props)\n        context.Send(child, msg)\n    }\n}\n\nfunc NewParentActor() actor.Actor {\n    return \u0026ParentActor{}\n}\n\ntype ChildActor struct{}\n\nfunc (state *ChildActor) Receive(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case *actor.Started:\n        fmt.Println(\"Starting, initialize actor here\")\n    case *actor.Stopping:\n        fmt.Println(\"Stopping, actor is about shut down\")\n    case *actor.Stopped:\n        fmt.Println(\"Stopped, actor and its children are stopped\")\n    case *actor.Restarting:\n        fmt.Println(\"Restarting, actor is about restart\")\n    case Hello:\n        fmt.Printf(\"Hello %v\\n\", msg.Who)\n        panic(\"Ouch\")\n    }\n}\n\nfunc NewChildActor() actor.Actor {\n    return \u0026ChildActor{}\n}\n\nfunc main() {\n\tdecider := func(reason interface{}) actor.Directive {\n\t\tlog.Printf(\"handling failure for child. reason:%v\", reason)\n\n\t\t// return actor.StopDirective\n\t\treturn actor.RestartDirective\n\t}\n\tsupervisor := actor.NewOneForOneStrategy(10, 1000, decider)\n\n\tctx := actor.NewActorSystem().Root\n\tprops := actor.PropsFromProducer(NewParentActor).WithSupervisor(supervisor)\n\n\tpid := ctx.Spawn(props)\n\tctx.Send(pid, Hello{Who: \"Roger\"})\n\n\tconsole.ReadLine()\n}\n```\n\n## Networking / Remoting\n\nProto Actor's networking layer is built as a thin wrapper ontop of gRPC and message serialization is built on Protocol\nBuffers\u003cbr/\u003e\n\n### Example\n\n#### Node 1\n\n```go\ntype MyActor struct {\n    count int\n}\n\nfunc (state *MyActor) Receive(context actor.Context) {\n    switch context.Message().(type) {\n    case *messages.Response:\n        state.count++\n        fmt.Println(state.count)\n    }\n}\n\nfunc main() {\n    remote.Start(\"localhost:8090\")\n\n    context := actor.EmptyRootContext\n    props := actor.PropsFromProducer(func() actor.Actor { return \u0026MyActor{} })\n    pid, _ := context.Spawn(props)\n    message := \u0026messages.Echo{Message: \"hej\", Sender: pid}\n\n    // this is to spawn remote actor we want to communicate with\n    spawnResponse, _ := remote.SpawnNamed(\"localhost:8091\", \"myactor\", \"hello\", time.Second)\n\n    // get spawned PID\n    spawnedPID := spawnResponse.Pid\n    for i := 0; i \u003c 10; i++ {\n        context.Send(spawnedPID, message)\n    }\n\n    console.ReadLine()\n}\n```\n\n#### Node 2\n\n```go\ntype MyActor struct{}\n\nfunc (*MyActor) Receive(context actor.Context) {\n    switch msg := context.Message().(type) {\n    case *messages.Echo:\n        context.Send(msg.Sender, \u0026messages.Response{\n            SomeValue: \"result\",\n        })\n    }\n}\n\nfunc main() {\n    remote.Start(\"localhost:8091\")\n\n    // register a name for our local actor so that it can be spawned remotely\n    remote.Register(\"hello\", actor.PropsFromProducer(func() actor.Actor { return \u0026MyActor{} }))\n    console.ReadLine()\n}\n```\n\n### Message Contracts\n\n```proto\nsyntax = \"proto3\";\npackage messages;\nimport \"actor.proto\"; // we need to import actor.proto, so our messages can include PID's\n\n// this is the message the actor on node 1 will send to the remote actor on node 2\nmessage Echo {\n  actor.PID Sender = 1; // this is the PID the remote actor should reply to\n  string Message = 2;\n}\n\n// this is the message the remote actor should reply with\nmessage Response {\n  string SomeValue = 1;\n}\n```\n\nNotice: always use \"gogoslick_out\" instead of \"go_out\" when generating proto code. \"gogoslick_out\" will create type\nnames which will be used during serialization.\n\nFor more examples, see the example folder in this repository.\n\n## Contributors\n\n\u003ca href=\"https://github.com/asynkron/protoactor-go/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contributors-img.web.app/image?repo=asynkron/protoactor-go\" /\u003e\n\u003c/a\u003e\n\nMade with [contributors-img](https://contributors-img.web.app). \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAsynkronIT%2Fprotoactor-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAsynkronIT%2Fprotoactor-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAsynkronIT%2Fprotoactor-go/lists"}