## File: README.md

[](https://ergo.services)

[](https://docs.ergo.services) [](https://pkg.go.dev/ergo.services/ergo) [](https://opensource.org/licenses/MIT) [](https://t.me/ergo_services) [](https://reddit.com/r/ergo_services) The Ergo Framework is an implementation of ideas, technologies, and design patterns from the Erlang world in the Go programming language. It is based on the actor model, network transparency, and a set of ready-to-use components for development. This significantly simplifies the creation of complex and distributed solutions while maintaining a high level of reliability and performance. ### Features ### 1. **Actor Model**: isolated processes communicate through message passing, handling messages sequentially in their own mailbox with four priority queues. Processes support both asynchronous messaging and synchronous request-response patterns, enabling flexible communication while maintaining the actor model guarantees. 2. **Network Transparency**: actors interact the same way whether local or remote. The framework uses custom serialization and protocol for [efficient](https://github.com/ergo-services/benchmarks) distributed communication with connection pooling, compression, and type caching, making network location transparent to application code. 3. **Supervision Trees**: hierarchical fault recovery where supervisors monitor child processes and apply restart strategies when failures occur. Supports multiple supervision types (One For One, All For One, Rest For One, Simple One For One) and restart strategies (Transient, Temporary, Permanent) for building self-healing systems. 4. **Meta Processes**: bridge blocking I/O with the actor model through dedicated meta processes that handle TCP, UDP, Port, and Web protocols. Meta processes run blocking operations without affecting regular actor message processing. 5. **Distributed Systems**: service discovery through embedded or external registrars (etcd, Saturn), distributed publish/subscribe events with token-based authorization and buffering, remote process spawning with factory-based permissions, and remote application orchestration across nodes. 6. **Ready-to-use Components**: core framework includes Actor, Supervisor, Pool, and WebWorker actors plus TCP, UDP, Port, and Web meta processes. Extra library provides Leader, Metrics actors, WebSocket, SSE meta processes, Observer application, Colored and Rotate loggers, Erlang protocol support. 7. **Flexibility**: customize network stack components, certificate management, compression and message priorities, logging, distributed events, and meta processes. Framework supports mTLS, NAT traversal, important delivery for guaranteed messaging, and Cron-based scheduling. Examples demonstrating the framework's capabilities are available in the [examples repository](https://github.com/ergo-services/examples). ### Benchmarks ### On a 64-core processor, Ergo Framework demonstrates a performance of **over 21 million messages per second locally** and **nearly 5 million messages per second over the network**. Available benchmarks can be found in the [benchmarks repository](https://github.com/ergo-services/benchmarks). * Messaging performance (local, network) * Memory consumption per process (demonstrates framework memory footprint) * Serialization performance comparison: EDF vs Protobuf vs Gob * Distributed Pub/Sub (event delivery to 1,000,000 subscribers across 10 nodes) ### Observer ### To inspect the node, network stack, running applications, and processes, you can use the [`observer`](https://github.com/ergo-services/tools/) tool To install the Observer tool, you need to have the Go compiler version 1.20 or higher. Run the following command: ``` $ go install ergo.tools/observer@latest ``` You can also embed the [Observer application](https://docs.ergo.services/extra-library/applications/observer) into your node. To see it in action, see the [demo example](https://github.com/ergo-services/examples/tree/master/demo). For more information, visit the [Observer documentation](https://docs.ergo.services/tools/observer). ### Quick start ### For a quick start, use the [`ergo`](https://docs.ergo.services/tools/ergo) tool — a command-line utility designed to simplify the process of generating boilerplate code for your project based on the Ergo Framework. With this tool, you can rapidly create a complete project structure, including applications, actors, supervisors, network components, and more. It offers a set of arguments that allow you to customize the project according to specific requirements, ensuring it is ready for immediate development. To install use the following command: ``` $ go install ergo.tools/ergo@latest ``` Now, you can create your project with just one command. Here is example: Supervision tree ``` mynode ├─ myapp │ │ │ └─ mysup │ │ │ └─ myactor ├─ myweb └─ myactor2 ``` To generate project for this design use the following command: ``` $ ergo -init MyNode \ -with-app MyApp \ -with-sup MyApp:MySup \ -with-actor MySup:MyActor \ -with-web MyWeb \ -with-actor MyActor2 \ -with-observer ``` as a result you will get generated project: ``` mynode ├── apps │ └── myapp │ ├── myactor.go │ ├── myapp.go │ └── mysup.go ├── cmd │ ├── myactor2.go │ ├── mynode.go │ ├── myweb.go │ └── myweb_worker.go ├── go.mod ├── go.sum └── README.md ``` to try it: ``` $ cd mynode $ go run ./cmd ``` Since we included Observer application, open http://localhost:9911 to inspect your node and running processes. ### Erlang support ### Starting from version 3.0.0, support for the Erlang network stack has been moved to a [separate module](https://github.com/ergo-services/proto). Version 3.0 was distributed under the BSL 1.1 license, but starting from version 3.1 it is available under the MIT license. Detailed information is available in the [Erlang protocol documentation](https://docs.ergo.services/extra-library/network-protocols/erlang). ### Requirements ### * Go 1.20.x and above ### Changelog ### Fully detailed changelog see in the [ChangeLog](CHANGELOG.md) file. #### [v3.2.0](https://github.com/ergo-services/ergo/releases/tag/v1.999.320) 2026-02-04 [tag version v1.999.320] #### * Introduced **mTLS support** - new `gen.CertAuthManager` interface for mutual TLS with CA pool management (`ClientCAs`, `RootCAs`, `ClientAuth`, `ServerName`). See [Mutual TLS](https://docs.ergo.services/networking/mutual-tls) documentation * Introduced **NAT support** - new `RouteHost` and `RoutePort` options in `gen.AcceptorOptions` for nodes behind NAT or load balancers. See [Behind the NAT](https://docs.ergo.services/networking/behind-the-nat) documentation * Introduced **spawn time control** - `InitTimeout` option in `gen.ProcessOptions` limits `ProcessInit` duration for both local and remote spawn. Remote spawn and application processes limited to max 15 seconds. See [Process](https://docs.ergo.services/basics/process) documentation * Introduced **zip-bomb protection** - decompression size limits to prevent memory exhaustion attacks * Added `gen.Ref` methods for request timeout tracking. See [Generic Types](https://docs.ergo.services/basics/generic-types#gen.ref): - `Deadline` - returns deadline timestamp stored in reference - `IsAlive` - checks if reference is still valid (deadline not exceeded) * Added `gen.Node` methods. See [Node](https://docs.ergo.services/basics/node) documentation: - `ProcessPID` / `ProcessName` - resolve process PID by name and vice versa - `Call`, `CallWithTimeout`, `CallWithPriority`, `CallImportant`, `CallPID`, `CallProcessID`, `CallAlias` - synchronous requests from Node interface - `Inspect` / `InspectMeta` - inspect processes and meta processes - `MakeRefWithDeadline` - create reference with embedded deadline * Added `gen.RemoteNode.ApplicationInfo` - query application information from remote nodes. See [Remote Start Application](https://docs.ergo.services/networking/remote-start-application) documentation * Added `gen.Process` methods. See [Process](https://docs.ergo.services/basics/process) documentation: - `SendWithPriorityAfter` - delayed send with priority - `SendExitAfter` / `SendExitMetaAfter` - delayed exit signals - `SendResponseImportant` / `SendResponseErrorImportant` - important delivery for responses * Added `gen.Meta` methods. See [Meta Process](https://docs.ergo.services/basics/meta-process) documentation: - `SendResponse` / `SendResponseError` - respond to requests from meta process - `SendPriority` / `SetSendPriority` - message priority control - `Compression` / `SetCompression` - compression settings - `EnvDefault` - get environment variable with default value * Added `gen.ApplicationSpec` / `gen.ApplicationInfo` fields: - `Tags` - labels for instance selection (blue/green, canary, maintenance). See [Tags for Instance Selection](https://docs.ergo.services/basics/application#tags-for-instance-selection) - `Map` - logical role to process name mapping. See [Process Role Mapping](https://docs.ergo.services/basics/application#process-role-mapping) * Added **HandleInspect** implementations for all supervisor types (OFO, ARFO, SOFO) * Fixed **LinkChild** in `RemoteNode.Spawn` / `RemoteNode.SpawnRegister` * Fixed **args persistence** for Simple One For One supervisor - child processes now restart with their original spawn arguments * Fixed **critical bug**: terminate signals (Link/Monitor exits) were incorrectly rejected due to wrong incarnation validation in network layer. Thanks to [@qjpcpu](https://github.com/qjpcpu) for reporting [#248](https://github.com/ergo-services/ergo/issues/248) * Completely reworked internal **Target Manager** (`node/tm/`) - improved architecture for process, event, and node target management with comprehensive test coverage * Completely reworked internal **Pub/Sub** mechanism - improved reliability and performance * Improved **ProcessInit state** - more `gen.Process` methods now available during initialization: - `Link*`, `Unlink*`, `Monitor*`, `Demonitor*` - `Call*`, `Inspect`, `InspectMeta` - `RegisterName`, `UnregisterName`, `RegisterEvent`, `UnregisterEvent` - `SendResponse*`, `SendResponseError*` - `CreateAlias`, `DeleteAlias` * Introduced **shutdown timeout** - `ShutdownTimeout` option in `gen.NodeOptions` (default 3 minutes). During graceful shutdown, pending processes are logged every 5 seconds with state and queue info. After timeout, node force exits with error code 1. See [Node](https://docs.ergo.services/basics/node) documentation * Added **pprof labels** for actor and meta process goroutines (with `--tags pprof`) - each process goroutine is labeled with its PID, each meta process with its Alias, making it easy to identify stuck processes in pprof output * Improved API documentation - comprehensive godoc comments for all public interfaces * **Documentation rewritten** - complete documentation now included in the repository (`docs/`) and available at [docs.ergo.services](https://docs.ergo.services) * New documentation articles: - [Project Structure](https://docs.ergo.services/basics/project-structure) - organizing projects with message isolation levels, deployment patterns, and evolution strategies - [Building a Cluster](https://docs.ergo.services/advanced/building-a-cluster) - step-by-step guide to distributed systems with service discovery, load balancing, and failover - [Message Versioning](https://docs.ergo.services/advanced/message-versioning) - evolving message contracts in distributed clusters with explicit versioning strategies - [Handle Sync](https://docs.ergo.services/advanced/handle-sync) - synchronous message handling patterns - [Important Delivery](https://docs.ergo.services/advanced/important-delivery) - guaranteed delivery mechanism - [Pub/Sub Internals](https://docs.ergo.services/advanced/pub-sub-internals) - event system architecture - [Debugging](https://docs.ergo.services/advanced/debugging) - build tags, pprof integration, troubleshooting stuck processes * **Extra Library - Actors** (https://github.com/ergo-services/actor): - Introduced **Leader** actor - distributed leader election with Raft-inspired consensus algorithm. Features: term-based disambiguation, automatic failover, split-brain prevention through majority quorum, dynamic peer discovery. See [documentation](https://docs.ergo.services/extra-library/actors/leader) - Introduced **Metrics** actor - Prometheus metrics exporter that collects node/network telemetry via HTTP endpoint. Features: automatic collection of node metrics (uptime, processes, memory), network metrics per remote node, extensible for custom metrics. See [documentation](https://docs.ergo.services/extra-library/actors/metrics) * **Extra Library - Meta Processes** (https://github.com/ergo-services/meta): - Introduced **SSE** (Server-Sent Events) meta-process - unidirectional server-to-client streaming over HTTP. Features: server handler for accepting connections, client connection for external SSE endpoints, full SSE spec support (event types, IDs, retry hints, multi-line data), process pool with round-robin load balancing, Last-Event-ID for reconnection. See [documentation](https://docs.ergo.services/extra-library/meta-processes/sse) * **Benchmarks** (https://github.com/ergo-services/benchmarks): - Introduced **Distributed Pub/Sub** benchmark - demonstrates event delivery to 1,000,000 subscribers across 10 nodes. Achieves 2.9M msg/sec delivery rate with only 10 network messages (one per consumer node) instead of 1M ### Development and debugging ### To enable Golang profiler just add `--tags pprof` in your `go run` or `go build` (profiler runs at `http://localhost:9009/debug/pprof`). Use `PPROF_HOST` and `PPROF_PORT` environment variables to customize the address. With `--tags pprof`, each actor goroutine is labeled with its PID and each meta process with its Alias for easy identification in pprof output: ``` curl -s "http://localhost:9009/debug/pprof/goroutine?debug=1" | grep -B5 'labels:.*pid' curl -s "http://localhost:9009/debug/pprof/goroutine?debug=1" | grep -B5 'labels:.*meta' ``` Output: ``` 1 @ 0x100c17fa0 ... # labels: {"pid":""} # main.(*Worker).HandleMessage+0x27 /path/worker.go:45 ``` This helps identify stuck processes during shutdown by matching PIDs/Aliases from the shutdown log with goroutine stack traces. To disable panic recovery use `--tags norecover`. To enable trace logging level for the internals (node, network,...) use `--tags trace` and set the log level `gen.LogLevelTrace` for your node. For detailed debugging techniques, troubleshooting scenarios, and best practices, see the [Debugging](https://docs.ergo.services/advanced/debugging) documentation. To run tests with cleaned test cache: ``` go vet go clean -testcache go test -v ./testing/tests/... ``` ### Commercial support please, contact support@ergo.services for more information --- ## File: docs/README.md # Overview Building reliable concurrent and distributed systems is hard. In Go, you might start with goroutines and channels. As the system grows, you add mutexes to protect shared state. Then you need to coordinate across multiple services, so you introduce message queues or RPC. Before long, you're managing synchronization primitives, handling partial failures, and debugging race conditions that only appear under load. Ergo Framework offers a different foundation. Think of it as making goroutines addressable and message-passing-only, then extending that model across a cluster. Processes are like goroutines - lightweight, multiplexed onto OS threads - but isolated and communicating only through messages. Each process has an identifier that works whether the process is local or on a remote node. Sending a message looks the same either way. The actor model isn't new. Erlang proved these patterns work for systems requiring massive concurrency and high reliability. Ergo brings them to Go: no external dependencies, familiar Go idioms, and performance that doesn't sacrifice correctness for speed. ## Core Components The framework consists of a few fundamental pieces that work together. A **node** provides the runtime environment. It manages process lifecycles, routes messages, handles network connections, and provides services like logging and scheduled tasks. When you start a node, you get infrastructure. When you spawn a process, the node handles the mechanics. **Processes** are lightweight actors. Each has a mailbox where messages queue up, priority-sorted into urgent, system, main, and log queues. The process handles messages one at a time in its own goroutine. When the mailbox empties, the goroutine sleeps. This makes processes efficient - you can have thousands without resource problems. It also makes them safe - sequential message handling means no race conditions within a process. **Supervision trees** provide fault tolerance. Supervisors monitor worker processes. When a worker crashes, the supervisor restarts it according to a configured strategy. Supervisors can supervise other supervisors, creating a hierarchy. Failures are isolated to subtrees. The rest of the system continues running while the failed part recovers. **Meta processes** solve a specific problem: integrating blocking I/O with the actor model. HTTP servers block waiting for requests. TCP servers block accepting connections. A meta process uses two goroutines - one runs your blocking code (like `http.ListenAndServe`), the other handles messages from other actors. This bridges synchronous APIs with asynchronous actor communication. ## Network Transparency The framework treats local and remote processes identically. Send a message to a process on the same node or a process on a remote node - the code is the same. The framework handles the difference. When you send to a remote process, the node extracts the target node from the process identifier, discovers that node's address (through static routes or a registrar), establishes a connection if needed, encodes the message, and sends it. The remote node receives it, decodes it, and delivers it to the target process's mailbox. This happens automatically. Your code just sends a message. This transparency extends to failure detection. Use the Important delivery flag and you get the same error semantics for remote processes as for local ones. Without it, a message to a missing remote process times out (was it slow or dead?). With it, you get immediate error notification (process doesn't exist), just like local delivery. The network becomes transparent not just for success cases but for failures too. Nodes discover each other through a registrar. By default, each node runs a minimal registrar. Nodes on the same host find each other through localhost. For remote nodes, the framework queries the registrar on the remote host. For production clusters, configure an external registrar like etcd or Saturn for centralized discovery, cluster configuration, and application deployment tracking. ## What This Enables You write business logic using message passing between processes. The framework handles concurrency (processes run in parallel but each is sequential internally), fault tolerance (supervisors restart failures), and distribution (messages route automatically to remote processes). You're not writing code to manage connections, encode messages, or handle network failures explicitly. Those are solved problems handled by the framework. Systems built this way have useful properties. They scale by adding nodes and distributing processes across them. The code doesn't change - deployment topology is operational configuration. They handle failures through supervision rather than defensive programming everywhere. They evolve through composition - add new process types, adjust supervision strategies, change message flows - without restructuring the foundation. The development experience differs from typical microservices. No REST endpoints to define. No service discovery to configure (it's built in). No serialization libraries to manage (the framework handles it). No retry logic scattered throughout (supervision handles recovery). You model your domain as processes exchanging messages, and the framework provides the infrastructure. ## Performance Lock-free queues in process mailboxes avoid contention. Processes sleep when idle, consuming no CPU. Connection pooling uses multiple TCP connections per remote node for parallel delivery. These design choices add up to performance comparable to hand-written concurrent code, but without the complexity. The real performance benefit is development velocity. You're not debugging race conditions or deadlocks. You're not coordinating distributed transactions. You're not managing connection pools or implementing retry logic. The framework handles those concerns, leaving you to focus on what your system does. Benchmarks measuring message passing, network communication, and serialization performance are available at [github.com/ergo-services/benchmarks](https://github.com/ergo-services/benchmarks). ## Zero Dependencies The framework uses only the Go standard library. No external dependencies means no version conflicts, no supply chain vulnerabilities, no surprise breaking changes from third-party packages. The requirement is just Go 1.20 or higher. This isn't ideological purity. It's practical stability. The framework's behavior depends only on Go itself. Updates are predictable. Supply chain is simple. The code you write today will compile and run the same way years from now, assuming Go maintains backward compatibility (which it does). For detailed explanations of these concepts, start with [Actor Model](basics/actor-model.md) and explore the [Basics](basics/actor-model.md) section. For API documentation, see the godoc comments in the source code.