github.com/ergo-services/ergo@v1.999.224/README.md (about)

     1  <h1><a href="https://ergo.services"><img src=".github/images/logo.svg" alt="Ergo Framework" width="159" height="49"></a></h1>
     2  
     3  <!--[![Gitbook Documentation](https://img.shields.io/badge/GitBook-Documentation-f37f40?style=plastic&logo=gitbook&logoColor=white&style=flat)](https://docs.ergo.services) -->
     4  [![GoDoc](https://pkg.go.dev/badge/ergo-services/ergo)](https://pkg.go.dev/github.com/ergo-services/ergo)
     5  [![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
     6  [![Telegram Community](https://img.shields.io/badge/Telegram-Community-blue?style=flat&logo=telegram)](https://t.me/ergo_services)
     7  [![Discord Community](https://img.shields.io/badge/Discord-Community-5865F2?style=flat&logo=discord&logoColor=white)](https://discord.gg/sdscxKGV62)
     8  [![Twitter](https://img.shields.io/badge/Twitter-ergo__services-1DA1F2?style=flat&logo=twitter&logoColor=white)](https://twitter.com/ergo_services)
     9  
    10  Technologies and design patterns of Erlang/OTP have been proven over the years. Now in Golang.
    11  Up to x5 times faster than original Erlang/OTP in terms of network messaging.
    12  The easiest way to create an OTP-designed application in Golang.
    13  
    14  [https://ergo.services](https://ergo.services)
    15  
    16  ### Purpose ###
    17  
    18  The goal of this project is to leverage Erlang/OTP experience with Golang performance. Ergo Framework implements [DIST protocol](https://erlang.org/doc/apps/erts/erl_dist_protocol.html), [ETF data format](https://erlang.org/doc/apps/erts/erl_ext_dist.html) and [OTP design patterns](https://erlang.org/doc/design_principles/des_princ.html) `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
    19  
    20  ### Cloud ###
    21  
    22  Distributed Cloud is coming. With Ergo Framework you can join your services into a single cluster with transparent networking using our **Cloud Overlay Network** where they can connect to each other smoothly, no matter where they run - AWS, Azure or GCP, or anywhere else. All these connections are secured with end-to-end encryption. Read more in this article [https://blog.ergo.services/cloud-overlay-network-3a133d47efe5](https://blog.ergo.services/cloud-overlay-network-3a133d47efe5).
    23  
    24  ### Quick start ###
    25  
    26  First, you need to install the boilerplate code generation tool `ergo` - https://github.com/ergo-services/tools using command below
    27  
    28  `go install ergo.services/tools/ergo@latest`
    29  
    30  And then, you can create your project with just one command. Here is example:
    31  
    32     Supervision tree
    33     ```
    34     mynode
    35     |- myapp
    36     |   |
    37     |    `- mysup
    38     |        |
    39     |         `- myactor
    40     |- myweb
    41     `- myactor2
    42     ```
    43  
    44     To generate project for this design use the following command:
    45  
    46     `ergo -init MyNode -with-app MyApp -with-sup MyApp:MySup -with-actor MySup:MyActor -with-web "MyWeb{port:8000,handlers:3}" -with-actor MyActor2`
    47  
    48     as a result you will get generated project:
    49  
    50     ```
    51        mynode/
    52        |-- apps/
    53        |   `-- myapp/
    54        |       |-- myactor.go
    55        |       |-- myapp.go
    56        |       `-- mysup.go
    57        |-- cmd/
    58        |   |-- myactor2.go
    59        |   |-- mynode.go
    60        |   |-- myweb.go
    61        |   `-- myweb_handler.go
    62        |-- README.md
    63        |-- go.mod
    64        `-- go.sum
    65     ```
    66  
    67     to try it:
    68     ```
    69     $ cd mynode
    70     $ go run ./cmd/
    71     ```
    72  
    73     You may also read our article about this tool with a great example https://blog.ergo.services/quick-start-1094d56d4e2
    74  
    75  ### Features ###
    76  
    77  ![image](https://user-images.githubusercontent.com/118860/113710255-c57d5500-96e3-11eb-9970-20f49008a990.png)
    78  
    79  * Support Erlang 25 - allows you connect your node to (and accept connection from) any Erlang/Elixir node within a cluster
    80  * Spawn Erlang-like processes
    81  * Register/unregister processes with simple atom
    82  * Set of ready-to-use disign patterns (behaviors)
    83    * `gen.Server` behavior with atomic state and Erlang's gen_server support to make sync request `ServerProcess.Call`, async - `ServerProcess.Cast` or `Process.Send` in fashion of `gen_server:call`, `gen_server:cast`, `erlang:send` accordingly
    84    * `gen.Supervisor` behavior with all known [restart strategies](https://erlang.org/doc/design_principles/sup_princ.html#restart-strategy) (One For One, One For All, Rest For One, Simple One For One)
    85    * `gen.Application` behavior with all known [starting types](https://erlang.org/doc/design_principles/applications.html#application-start-types) (Permanent, Temporary, Transient)
    86    * `gen.Pool` a basic design pattern with a pool of workers. All messages/requests received by the pool process are forwarded to the workers using the "Round Robin" algorithm. The worker process is automatically restarting on termination
    87    * `gen.TCP` - socket acceptor pool for TCP protocols. This behavior aims to provide everything you need to accept TCP connections and process packets with a small code base and low latency while being easy to use.
    88    * `gen.UDP` - acceptor pool for UDP protocols. This behavior provides the same feature set as TCP but for handling UDP packets using pool of handlers
    89    * `gen.Web` - Web API Gateway behavior. This behavior allows you to listen HTTP port and handle HTTP-request using pool of workers.
    90    * `gen.Stage` behavior support (originated from Elixir's [GenStage](https://hexdocs.pm/gen_stage/GenStage.html)). 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](https://github.com/ergo-services/examples/tree/master/genstage) or just run `go run ./examples/genstage` to see it in action
    91    * `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](https://github.com/ergo-services/examples/tree/master/gensaga).
    92    * `gen.Raft` behavior support. It's improved implementation of [Raft consensus algorithm](https://raft.github.io). 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/genraft](https://github.com/ergo-services/examples/tree/master/genraft)
    93  * Monitor processes/nodes, local/remote with Erlang support
    94  * Link processes local/remote with Erlang support
    95  * [embedded EPMD](#epmd) (in order to get rid of erlang' dependencies) with Erlang support
    96  * Unmarshalling terms into the struct using `etf.TermIntoStruct`, `etf.TermProplistIntoStruct` or to the string using `etf.TermToString` including custom marshaling/unmarshaling via `Marshal` and `Unmarshal` interfaces. But it's highly recommended to use `etf.RegisterType` so you will be receiving messages in a native Golang-type
    97  * Encryption (TLS 1.3) support (including autogenerating self-signed certificates)
    98  * Compression support (with customization of compression level and threshold). It can be configured for the node or a particular process.
    99  * Proxy support with end-to-end encryption, includeing compression/fragmentation/linking/monitoring features.
   100  * Tested and confirmed support Windows, Darwin (MacOS), Linux, FreeBSD.
   101  * Zero dependencies. All features are implemented using the standard Golang library.
   102  
   103  ### Requirements ###
   104  
   105  * Go 1.17.x and above
   106  
   107  ### Versioning ###
   108  
   109  Golang introduced [v2 rule](https://go.dev/blog/v2-go-modules) 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.
   110  
   111  ### Changelog ###
   112  
   113  Here are the changes of latest release. For more details see the [ChangeLog](ChangeLog.md)
   114  
   115  #### [v2.2.4](https://github.com/ergo-services/ergo/releases/tag/v1.999.224) 2023-05-01 [tag version v1.999.224] ####
   116  
   117  This release includes fixes:
   118  - Fixed incorrect handling of `gen.SupervisorStrategyRestartTransient` restart strategy in `gen.Supervisor`
   119  - Fixed missing `ServerBehavior` in [`gen.Pool`, `gen.Raft`, `gen.Saga`, `gen.Stage`, `gen.TCP`, `gen.UDP`, `gen.Web`] behavior interfaces
   120  - Introduced the new tool for boilerplate code generation - `ergo` https://github.com/ergo-services/tools. You may read more information about this tool in our article with a great example https://blog.ergo.services/quick-start-1094d56d4e2
   121  
   122  ### Benchmarks ###
   123  
   124  Here is simple EndToEnd test demonstrates performance of messaging subsystem
   125  
   126  Hardware: workstation with AMD Ryzen Threadripper 3970X (64) @ 3.700GHz
   127  
   128  ```
   129  ❯❯❯❯ go test -bench=NodeParallel -run=XXX -benchtime=10s
   130  goos: linux
   131  goarch: amd64
   132  pkg: github.com/ergo-services/ergo/tests
   133  cpu: AMD Ryzen Threadripper 3970X 32-Core Processor
   134  BenchmarkNodeParallel-64                 4738918              2532 ns/op
   135  BenchmarkNodeParallelSingleNode-64      100000000              429.8 ns/op
   136  
   137  PASS
   138  ok      github.com/ergo-services/ergo/tests  29.596s
   139  ```
   140  
   141  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).
   142  
   143  #### Compression
   144  
   145  This benchmark shows the performance of compression for sending 1MB message between two nodes (via a network).
   146  
   147  ```
   148  ❯❯❯❯ go test -bench=NodeCompression -run=XXX -benchtime=10s
   149  goos: linux
   150  goarch: amd64
   151  pkg: github.com/ergo-services/ergo/tests
   152  cpu: AMD Ryzen Threadripper 3970X 32-Core Processor
   153  BenchmarkNodeCompressionDisabled1MBempty-64         2400           4957483 ns/op
   154  BenchmarkNodeCompressionEnabled1MBempty-64          5769           2088051 ns/op
   155  BenchmarkNodeCompressionEnabled1MBstring-64         5202           2077099 ns/op
   156  PASS
   157  ok      github.com/ergo-services/ergo/tests     56.708s
   158  ```
   159  
   160  It demonstrates **more than 2 times** improvement.
   161  
   162  #### Proxy
   163  
   164  This benchmark demonstrates how proxy feature and e2e encryption impact a messaging performance.
   165  
   166  ```
   167  ❯❯❯❯ go test -bench=NodeProxy -run=XXX -benchtime=10s
   168  goos: linux
   169  goarch: amd64
   170  pkg: github.com/ergo-services/ergo/tests
   171  cpu: AMD Ryzen Threadripper 3970X 32-Core Processor
   172  BenchmarkNodeProxy_NodeA_to_NodeC_direct_Message_1KB-64                     1908477       6337 ns/op
   173  BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1KB-64                  1700984       7062 ns/op
   174  BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1KB_Encrypted-64        1271125       9410 ns/op
   175  PASS
   176  ok      github.com/ergo-services/ergo/tests     45.649s
   177  
   178  ```
   179  
   180  
   181  #### Ergo Framework vs original Erlang/OTP
   182  
   183  Hardware: laptop with Intel(R) Core(TM) i5-8265U (4 cores. 8 with HT)
   184  
   185  ![benchmarks](https://raw.githubusercontent.com/halturin/ergobenchmarks/master/ergobenchmark.png)
   186  
   187  sources of these benchmarks are [here](https://github.com/halturin/ergobenchmarks)
   188  
   189  
   190  ### EPMD ###
   191  
   192  *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.
   193  
   194  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.
   195  
   196  ### Examples ###
   197  
   198  Code below is a simple implementation of gen.Server pattern [examples/genserver](https://github.com/ergo-services/examples/tree/master/genserver)
   199  
   200  ```golang
   201  package main
   202  
   203  import (
   204  	"fmt"
   205  	"time"
   206  
   207  	"github.com/ergo-services/ergo/etf"
   208  	"github.com/ergo-services/ergo/gen"
   209  )
   210  
   211  type simple struct {
   212  	gen.Server
   213  }
   214  
   215  func (s *simple) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
   216  	value := message.(int)
   217  	fmt.Printf("HandleInfo: %#v \n", message)
   218  	if value > 104 {
   219  		return gen.ServerStatusStop
   220  	}
   221  	// sending message with delay 1 second
   222  	fmt.Println("increase this value by 1 and send it to itself again")
   223  	process.SendAfter(process.Self(), value+1, time.Second)
   224  	return gen.ServerStatusOK
   225  }
   226  
   227  ```
   228  
   229  here is output of this code
   230  
   231  ```shell
   232  $ go run ./examples/simple
   233  HandleInfo: 100
   234  HandleInfo: 101
   235  HandleInfo: 102
   236  HandleInfo: 103
   237  HandleInfo: 104
   238  HandleInfo: 105
   239  exited
   240  ```
   241  
   242  See [https://github.com/ergo-services/examples](https://github.com/ergo-services/examples/) for more details
   243  
   244  * [gen.Application](https://github.com/ergo-services/examples/tree/master/application)
   245  * [gen.Supervisor](https://github.com/ergo-services/examples/tree/master/supervisor)
   246  * [gen.Server](https://github.com/ergo-services/examples/tree/master/genserver)
   247  * [gen.Pool](https://github.com/ergo-services/examples/tree/master/genpool)
   248  * [gen.Stage](https://github.com/ergo-services/examples/tree/master/genstage)
   249  * [gen.Saga](https://github.com/ergo-services/examples/tree/master/gensaga)
   250  * [gen.Raft](https://github.com/ergo-services/examples/tree/master/genraft)
   251  * [gen.Custom](https://github.com/ergo-services/examples/tree/master/gencustom)
   252  * [gen.Web](https://github.com/ergo-services/examples/tree/master/genweb)
   253  * [gen.TCP](https://github.com/ergo-services/examples/tree/master/gentcp)
   254  * [gen.UDP](https://github.com/ergo-services/examples/tree/master/genudp)
   255  * [events](https://github.com/ergo-services/examples/tree/master/events)
   256  * [erlang](https://github.com/ergo-services/examples/tree/master/erlang)
   257  * [proxy](https://github.com/ergo-services/examples/tree/master/proxy)
   258  * [cloud](https://github.com/ergo-services/examples/tree/master/cloud)
   259  
   260  ### Elixir Phoenix Users ###
   261  
   262  Users of the Elixir Phoenix framework might encounter timeouts when trying to connect a Phoenix node
   263  to an ergo node. The reason is that, in addition to global_name_server and net_kernel,
   264  Phoenix attempts to broadcast messages to the [pg2 PubSub handler](https://hexdocs.pm/phoenix/1.1.0/Phoenix.PubSub.PG2.html)
   265  
   266  To work with Phoenix nodes, you must create and register a dedicated pg2 GenServer, and
   267  spawn it inside your node. The spawning process must have "pg2" as a process name:
   268  
   269  ```golang
   270  type Pg2GenServer struct {
   271      gen.Server
   272  }
   273  
   274  func main() {
   275      // ...
   276      pg2 := &Pg2GenServer{}
   277      node1, _ := ergo.StartNode("node1@localhost", "cookies", node.Options{})
   278      process, _ := node1.Spawn("pg2", gen.ProcessOptions{}, pg2, nil)
   279      // ...
   280  }
   281  ```
   282  
   283  ### Development and debugging ###
   284  
   285  There are options already defined that you might want to use
   286  
   287  * `-ergo.trace` - enable debug info (logging via `lib.Log(...)`)
   288  * `-ergo.debug` - enable extended debug info (logging via `lib.Log(...)` and `lib.Warning(...)`)
   289  * `-ergo.norecover` - disable panic catching
   290  * `-ergo.warning` - enable/disable warnings (logging via `lib.Warning(...)`. Default: enable)
   291  
   292  To enable Golang profiler just add `--tags debug` in your `go run` or `go build` like this:
   293  
   294  ```
   295  go run --tags debug ./examples/genserver/demoGenServer.go
   296  ```
   297  
   298  Now golang' profiler is available at `http://localhost:9009/debug/pprof`
   299  
   300  To check test coverage:
   301  
   302  ```
   303  go test -coverprofile=cover.out ./...
   304  go tool cover -html=cover.out -o coverage.html
   305  ```
   306  
   307  To run tests with cleaned test cache:
   308  
   309  ```
   310  go vet
   311  go clean -testcache
   312  go test -v ./...
   313  ```
   314  
   315  To run benchmarks:
   316  
   317  ```
   318  go test -bench=Node -run=X -benchmem
   319  ```
   320  
   321  ### Companies are using Ergo Framework ###
   322  
   323  [![Kaspersky](.github/images/kaspersky.png)](https://kaspersky.com)
   324  [![RingCentral](.github/images/ringcentral.png)](https://www.ringcentral.com)
   325  [![LilithGames](.github/images/lilithgames.png)](https://lilithgames.com)
   326  
   327  is your company using Ergo? add your company logo/name here
   328  
   329  ### Commercial support
   330  
   331  please, contact ceo@ergo.services for more information