https://github.com/ergo-services/ergo Skip to content Sign up * Product + Features + Mobile + Actions + Codespaces + Packages + Security + Code review + Issues + Integrations + GitHub Sponsors + Customer stories * Team * Enterprise * Explore + Explore GitHub + Learn and contribute + Topics + Collections + Trending + Skills + GitHub Sponsors + Open source guides + Connect with others + The ReadME Project + Events + Community forum + GitHub Education + GitHub Stars program * Marketplace * Pricing + Plans + Compare plans + Contact Sales + Education [ ] * # In this repository All GitHub | Jump to | * No suggested jump to results * # In this repository All GitHub | Jump to | * # In this organization All GitHub | Jump to | * # In this repository All GitHub | Jump to | Sign in Sign up {{ message }} ergo-services / ergo Public * * Notifications * Fork 80 * Star 1.4k an actor based Framework for creating microservices using technologies and design patterns of Erlang/OTP in Golang ergo.services License MIT license 1.4k stars 80 forks Star Notifications * Code * Issues 9 * Pull requests 0 * Discussions * Actions * Security * Insights More * Code * Issues * Pull requests * Discussions * Actions * Security * Insights ergo-services/ergo This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. master Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags 3 branches 16 tags Code Latest commit @halturin halturin Create CONTRIBUTING.md ... 513c907 May 17, 2022 Create CONTRIBUTING.md 513c907 Git stats * 184 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .github V210 (#98) Apr 19, 2022 erlang V210 (#98) Apr 19, 2022 etf V210 (#98) Apr 19, 2022 examples V210 (#98) Apr 19, 2022 gen V210 (#98) Apr 19, 2022 lib V210 (#98) Apr 19, 2022 node V210 (#98) Apr 19, 2022 proto/dist V210 (#98) Apr 19, 2022 tests V210 (#98) Apr 19, 2022 .gitignore V210 (#98) Apr 19, 2022 CODE_OF_CONDUCT.md Create CODE_OF_CONDUCT.md May 17, 2022 CONTRIBUTING.md Create CONTRIBUTING.md May 17, 2022 ChangeLog.md V210 (#98) Apr 19, 2022 LICENSE Update formatting LICENSE file Dec 10, 2020 README.md Update README.md Apr 19, 2022 debug.go V210 (#98) Apr 19, 2022 ergo.go V210 (#98) Apr 19, 2022 go.mod V210 (#98) Apr 19, 2022 go.sum Supervisor (#15) Feb 28, 2020 version.go V210 (#98) Apr 19, 2022 View code [ ] Purpose Features Requirements Versioning Changelog v2.1.0 2022-04-19 [tag version v1.999.210] Benchmarks Compression Proxy Ergo Framework vs original Erlang/OTP EPMD Observer Examples Elixir Phoenix Users Development and debugging Companies are using Ergo Framework Commercial support README.md Ergo Framework GoDoc Build Status Telegram Community Discord Community Twitter MIT license Technologies and design patterns of Erlang/OTP have been proven over the years. Now in Golang. Up to x5 times faster than original Erlang/ OTP in terms of network messaging. The easiest way to create an OTP-designed application in Golang. https://ergo.services Purpose The goal of this project is to leverage Erlang/OTP experience with Golang performance. Ergo Framework implements DIST protocol, ETF data format and OTP design patterns gen.Server, gen.Supervisor, gen.Application which makes you able to create distributed, high performance and reliable microservice solutions having native integration with Erlang infrastructure Features image * Support Erlang 24 (including Alias and Remote Spawn features) * Spawn Erlang-like processes * Register/unregister processes with simple atom * gen.Server behavior support (with atomic state) * gen.Supervisor behavior support with all known restart strategies support + One For One + One For All + Rest For One + Simple One For One * gen.Application behavior support with all known starting types support + Permanent + Temporary + Transient * gen.Stage behavior support (originated from Elixir's GenStage). This is abstraction built on top of gen.Server to provide a simple way to create a distributed Producer/Consumer architecture, while automatically managing the concept of backpressure. This implementation is fully compatible with Elixir's GenStage. Example is here examples/genstage or just run go run ./examples/genstage to see it in action * gen.Saga behavior support. It implements Saga design pattern - a sequence of transactions that updates each service state and publishes the result (or cancels the transaction or triggers the next transaction step). gen.Saga also provides a feature of interim results (can be used as transaction progress or as a part of pipeline processing), time deadline (to limit transaction lifespan), two-phase commit (to make distributed transaction atomic). Here is example examples/gensaga. * gen.Raft behavior support. It's improved implementation of Raft consensus algorithm. The key improvement is using quorum under the hood to manage the leader election process and make the Raft cluster more reliable. This implementation supports quorums of 3, 5, 7, 9, or 11 quorum members. Here is an example of this feature examples/raft. * Connect to (accept connection from) any Erlang/Elixir node within a cluster * Making sync request ServerProcess.Call, async - ServerProcess.Cast or Process.Send in fashion of gen_server:call, gen_server:cast, erlang:send accordingly * Monitor processes/nodes, local/remote * Link processes local/remote * RPC callbacks support * embedded EPMD (in order to get rid of erlang' dependencies) * Unmarshalling terms into the struct using etf.TermIntoStruct, etf.TermProplistIntoStruct or to the string using etf.TermToString * Custom marshaling/unmarshaling via Marshal and Unmarshal interfaces * Encryption (TLS 1.3) support (including autogenerating self-signed certificates) * Compression support (with customization of compression level and threshold). It can be configured for the node or a particular process. * Proxy support with end-to-end encryption, includeing compression/ fragmentation/linking/monitoring features. * Tested and confirmed support Windows, Darwin (MacOS), Linux, FreeBSD. * Zero dependencies. All features are implemented using the standard Golang library. Requirements * Go 1.17.x and above Versioning Golang introduced v2 rule a while ago to solve complicated dependency issues. We found this solution very controversial and there is still a lot of discussion around it. So, we decided to keep the old way for the versioning, but have to use the git tag with v1 as a major version (due to "v2 rule" restrictions). Since now we use git tag pattern 1.999.XYZ where X - major number, Y - minor, Z - patch version. Changelog Here are the changes of latest release. For more details see the ChangeLog v2.1.0 2022-04-19 [tag version v1.999.210] * Introduced compression feature support. Here are new methods and options to manage this feature: + gen.Process: o SetCompression(enable bool), Compression() bool o SetCompressionLevel(level int) bool, CompressionLevel() int o SetCompressionThreshold(threshold int) bool, CompressionThreshold() int messages smaller than the threshold will be sent with no compression. The default compression threshold is 1024 bytes. + node.Options: o Compression these settings are used as defaults for the spawning processes + this feature will be ignored if the receiver is running on either the Erlang or Elixir node * Introduced proxy feature support with end-to-end encryption. + node.Node new methods: o AddProxyRoute(...), RemoveProxyRoute(...) o ProxyRoute(...), ProxyRoutes() o NodesIndirect() returns list of connected nodes via proxy connection + node.Options: o Proxy for configuring proxy settings + includes support (over the proxy connection): compression, fragmentation, link/monitor process, monitor node + example examples/proxy. + this feature is not available for the Erlang/Elixir nodes * Introduced behavior gen.Raft. It's improved implementation of Raft consensus algorithm. The key improvement is using quorum under the hood to manage the leader election process and make the Raft cluster more reliable. This implementation supports quorums of 3, 5, 7, 9, or 11 quorum members. Here is an example of this feature examples/raft. * Introduced interfaces to customize network layer + Resolver to replace EPMD routines with your solution (e.g., ZooKeeper or any other service registrar) + Handshake allows customizing authorization/authentication process + Proto provides the way to implement proprietary protocols (e.g., IoT area) * Other new features: + gen.Process new methods: o NodeUptime(), NodeName(), NodeStop() + gen.ServerProcess new method: o MessageCounter() shows how many messages have been handled by the gen.Server callbacks + gen.ProcessOptions new option: o ProcessFallback allows forward messages to the fallback process if the process mailbox is full. Forwarded messages are wrapped into gen.MessageFallback struct. Related to issue #96. + gen.SupervisorChildSpec and gen.ApplicationChildSpec got option gen.ProcessOptions to customize options for the spawning child processes. * Improved sending messages by etf.Pid or etf.Alias: methods gen.Process.Send, gen.ServerProcess.Cast, gen.ServerProcess.Call now return node.ErrProcessIncarnation if a message is sending to the remote process of the previous incarnation (remote node has been restarted). Making monitor on a remote process of the previous incarnation triggers sending gen.MessageDown with reason incarnation. * Introduced type gen.EnvKey for the environment variables * All spawned processes now have the node.EnvKeyNode variable to get access to the node.Node value. * Improved performance of local messaging (up to 8 times for some cases) * Important node.Options has changed. Make sure to adjust your code. * Fixed issue #89 (incorrect handling of Call requests) * Fixed issues #87, #88 and #93 (closing network socket) * Fixed issue #96 (silently drops message if process mailbox is full) * Updated minimal requirement of Golang version to 1.17 (go.mod) * We still keep the rule Zero Dependencies Benchmarks Here is simple EndToEnd test demonstrates performance of messaging subsystem Hardware: workstation with AMD Ryzen Threadripper 3970X (64) @ 3.700GHz go test -bench=NodeParallel -run=XXX -benchtime=10s goos: linux goarch: amd64 pkg: github.com/ergo-services/ergo/tests cpu: AMD Ryzen Threadripper 3970X 32-Core Processor BenchmarkNodeParallel-64 4738918 2532 ns/op BenchmarkNodeParallelSingleNode-64 100000000 429.8 ns/op PASS ok github.com/ergo-services/ergo/tests 29.596s these numbers show almost 500.000 sync requests per second for the network messaging via localhost and 10.000.000 sync requests per second for the local messaging (within a node). Compression This benchmark shows the performance of compression for sending 1MB message between two nodes (via a network). go test -bench=NodeCompression -run=XXX -benchtime=10s goos: linux goarch: amd64 pkg: github.com/ergo-services/ergo/tests cpu: AMD Ryzen Threadripper 3970X 32-Core Processor BenchmarkNodeCompressionDisabled1MBempty-64 2400 4957483 ns/op BenchmarkNodeCompressionEnabled1MBempty-64 5769 2088051 ns/op BenchmarkNodeCompressionEnabled1MBstring-64 5202 2077099 ns/op PASS ok github.com/ergo-services/ergo/tests 56.708s It demonstrates more than 2 times improvement. Proxy This benchmark demonstrates how proxy feature and e2e encryption impact a messaging performance. go test -bench=NodeProxy -run=XXX -benchtime=10s goos: linux goarch: amd64 pkg: github.com/ergo-services/ergo/tests cpu: AMD Ryzen Threadripper 3970X 32-Core Processor BenchmarkNodeProxy_NodeA_to_NodeC_direct_Message_1KB-64 1908477 6337 ns/op BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1KB-64 1700984 7062 ns/op BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1KB_Encrypted-64 1271125 9410 ns/op PASS ok github.com/ergo-services/ergo/tests 45.649s Ergo Framework vs original Erlang/OTP Hardware: laptop with Intel(R) Core(TM) i5-8265U (4 cores. 8 with HT) benchmarks sources of these benchmarks are here EPMD Ergo Framework has embedded EPMD implementation in order to run your node without external epmd process needs. By default, it works as a client with erlang' epmd daemon or others ergo's nodes either. The one thing that makes embedded EPMD different is the behavior of handling connection hangs - if ergo' node is running as an EPMD client and lost connection, it tries either to run its own embedded EPMD service or to restore the lost connection. Observer It's a standard Erlang tool. Observer is a graphical tool for observing the characteristics of Erlang systems. The tool Observer displays system information, application supervisor trees, process information. Here you can see this feature in action using one of the examples: observer demo Examples Code below is a simple implementation of gen.Server pattern examples/ simple package main import ( "fmt" "time" "github.com/ergo-services/ergo" "github.com/ergo-services/ergo/etf" "github.com/ergo-services/ergo/gen" "github.com/ergo-services/ergo/node" ) // simple implementation of Server type simple struct { gen.Server } func (s *simple) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { value := message.(int) fmt.Printf("HandleInfo: %#v \n", message) if value > 104 { return gen.ServerStatusStop } // sending message with delay process.SendAfter(process.Self(), value+1, time.Duration(1*time.Second)) return gen.ServerStatusOK } func main() { // create a new node node, _ := ergo.StartNode("node@localhost", "cookies", node.Options{}) // spawn a new process of gen.Server process, _ := node.Spawn("gs1", gen.ProcessOptions{}, &simple{}) // send a message to itself process.Send(process.Self(), 100) // wait for the process termination. process.Wait() fmt.Println("exited") node.Stop() } here is output of this code $ go run ./examples/simple HandleInfo: 100 HandleInfo: 101 HandleInfo: 102 HandleInfo: 103 HandleInfo: 104 HandleInfo: 105 exited See examples/ for more details * gen.Application * gen.Supervisor * gen.Server * gen.Stage * gen.Saga * gen.Demo * Node with TLS * Node with HTTP server Elixir Phoenix Users Users of the Elixir Phoenix framework might encounter timeouts when trying to connect a Phoenix node to an ergo node. The reason is that, in addition to global_name_server and net_kernel, Phoenix attempts to broadcast messages to the pg2 PubSub handler To work with Phoenix nodes, you must create and register a dedicated pg2 GenServer, and spawn it inside your node. The spawning process must have "pg2" as a process name: type Pg2GenServer struct { gen.Server } func main() { // ... pg2 := &Pg2GenServer{} node1, _ := ergo.StartNode("node1@localhost", "cookies", node.Options{}) process, _ := node1.Spawn("pg2", gen.ProcessOptions{}, pg2, nil) // ... } Development and debugging There are options already defined that you might want to use * -ergo.trace - enable extended debug info * -ergo.norecover - disable panic catching * -ergo.warning - enable/disable warnings (default: enable) To enable Golang profiler just add --tags debug in your go run or go build like this: go run --tags debug ./examples/genserver/demoGenServer.go Now golang' profiler is available at http://localhost:9009/debug/ pprof To check test coverage: go test -coverprofile=cover.out ./... go tool cover -html=cover.out -o coverage.html To run tests with cleaned test cache: go vet go clean -testcache go test -v ./... To run benchmarks: go test -bench=Node -run=X -benchmem Companies are using Ergo Framework Kaspersky RingCentral LilithGames is your company using Ergo? add your company logo/name here Commercial support please, visit https://ergo.services for more information About an actor based Framework for creating microservices using technologies and design patterns of Erlang/OTP in Golang ergo.services Topics go golang distributed-systems framework erlang elixir otp actors microservice worker beam actor-model supervisor distributed rpc interop mesh microservices-architecture otp-applications erlang-node Resources Readme License MIT license Code of conduct Code of conduct Stars 1.4k stars Watchers 38 watching Forks 80 forks Releases 14 v2.1.0 Latest Apr 19, 2022 + 13 releases Sponsor this project Used by 9 * @okkdev * @khanakia * @d-led * @MeshBoxFoundation * @MeshBoxFoundation * @ut-proj * @wqdotnet + 1 Contributors 10 * @halturin * @Zert * @ftrvxmtrx * @mdevilliers * @mytholog * @AlexKovalevych * @juise * @rutaka-n * @Larrouse2015 * @dmitrivereshchagin Languages * Go 100.0% * (c) 2022 GitHub, Inc. * Terms * Privacy * Security * Status * Docs * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time. You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.