Node
What is a Node in Ergo Framework?
A Node is the core of the service you create using Ergo Framework. This core includes:
Process Management Subsystem: handles the starting/stopping of processes, and the registration of process names/aliases.
Message Routing Subsystem: manages the routing of asynchronous messages and synchronous requests between processes.
Pub/Sub Subsystem: powers the event, link, and monitor functionalities, enabling distributed event handling.
Network Stack: provides service discovery and network transparency, facilitating seamless communication between nodes.
Logging Subsystem
Starting a node
To start a node, the first step is to define its name. The name consists of two parts: <name>@<hostname>
, where the hostname determines on which network interface the port for incoming connections will be opened.
The node's name must be unique on the host. This means that two nodes with the same name cannot be running on the same host.
Below is an example code for starting a node:
If the gen.NodeOptions.Applications
option includes applications when starting the node, they will be automatically loaded and started. However, if any application fails to start, the ergo.StartNode(...)
function will return an error, and the node will shut down. Upon a successful start, this function returns the gen.Node
interface.
You can also specify environment variables for the node using the Env
option in gen.NodeOptions
. All processes started on this node will inherit these variables. The gen.Node
interface provides the ability to manage environment variables through methods like EnvList()
, SetEnv(...)
, and Env(...)
. However, changes to environment variables will only affect newly started processes. Environment variable names are case-insensitive.
Additionally, the gen.Node
interface provides the following methods:
Starting/Stopping Processes: methods like
Spawn(...)
,SpawnRegister(...)
allow you to start processes, whileKill(...)
andSendExit(...)
are used to stop them.Retrieving Process Information: use the
ProcessInfo(...)
method to get information about a process, and theMetaInfo(...)
method to retrieve information about meta-processes.Managing the Node's Network Stack: access the
gen.Network
interface through theNetwork()
method to manage the node's network operations.Getting Node Uptime: the
Uptime()
method provides the node's uptime in seconds.General Node Information: use the
Info()
method to retrieve general information about the node.Sending Asynchronous Messages: the
Send(...)
method allows you to send asynchronous messages to a process.
The full list of available methods for the gen.Node
interface can be found in the reference documentation.
Process management
The mechanism for starting and stopping processes is provided by the node's core. Each process is assigned a unique identifier, gen.PID
, which facilitates message routing.
The node also allows you to register a name associated with a process. You can register such a name at the time of process startup by using the SpawnRegister
method and specifying the desired name. Alternatively, you can use the RegisterName
method from the gen.Node
or gen.Process
interfaces to assign a name to an already running process.
A process can only have one associated name. If you want to change a process's name, you must first unregister the existing name using the UnregisterName
method from the gen.Node
or gen.Process
interfaces. Upon success, this method returns the gen.PID
of the process previously associated with that name.
A process can be terminated by the node by sending it an exit signal. This is done via the SendExit
method in the gen.Node
interface. If necessary, the node can also forcefully stop a process using the Kill
method provided by the gen.Node
interface.
Message routing
One of the key responsibilities of a node is message routing between processes. This routing is transparent to both the sender and the receiver processes. If the recipient process is located on a remote node, the node will automatically attempt to establish a network connection to the remote node and deliver the message to the recipient. This is the network transparency provided by the Ergo Framework—you don't need to worry about how to send the message or how to encode it, as the node handles all of this automatically and transparently for you.
Message routing is not limited to the gen.PID
process identifier. A message can also be addressed using:
Local Process Name (
gen.Atom
): messages can be sent to a local process by referencing its registered name.gen.Alias
: this is a unique identifier that can be created by the process itself. It is often used for meta-processes or as a process temporary identifier. You can read more about this feature in the Process section.gen.ProcessID
: This is used for sending messages by the recipient process's name. The structure contains two fields—Name
andNode
. It is a convenient way to send a message to a process on a remote node when you do not know thegen.PID
orgen.Alias
of the remote process.
Through these flexible options, the Ergo Framework provides a robust and seamless message routing system, simplifying communication between processes whether they are local or remote.
Pub/Sub subsystem
The core of the node implements a publisher/subscriber mechanism, which serves as the foundation for process linking, monitoring, and connections with other nodes.
Monitoring Functionality: this allows any process to monitor other processes or nodes. In the event that a monitored process stops or the connection to a node is lost, the process that created the monitor will receive a
gen.MessageDownPID
orgen.MessageDownNode
message, respectively.Linking Functionality: similar to monitoring, linking differs in that when a linked process terminates or the connection to a node is lost, the process that created the link will receive an exit signal, causing it to stop as well.
Event System: the publisher/subscriber mechanism is also used in the events functionality. It allows any process to register its own event type and act as a producer of those events, while other processes can subscribe to those events.
Thanks to network transparency, the pub/sub subsystem works not only for local processes but also for remote ones.
You can read more about these features in the sections on Links and Monitors and Events.
Network stack
The process of sending a message to a remote node involves several steps:
Connection Establishment: if a connection to the remote node has not yet been created, the node queries the registrar on the host where the target node (owner of the recipient
gen.PID
,gen.ProcessID
, orgen.Alias
) is running. The registrar returns the port number on which the target node accepts incoming connections. The connection to this node is then established. This connection remains active until one of the nodes explicitly closes it by callingDisconnect
from thegen.RemoteNode
interface.Message Encoding: the message is encoded into the binary EDF format.
Data Compression: if compression was enabled for the sender process, the binary data is compressed.
Message Transmission: the message is sent over the network using the ENP protocol.
Message Decoding and Delivery: remote node automatically decodes the received message and ensures its delivery to the recipient process's mailbox.
For more detailed information on network interactions, refer to the Network Stack section.
Node shutdown
You can stop a node using the Stop()
or StopForce()
methods from the gen.Node
interface.
Stop
: all processes will be sent an exit signal with the reasongen.TerminateReasonShutdown
from the parent process, and the node will wait for all processes to terminate. Once all processes have stopped, the node's network stack and the node itself will be shut down.StopForce
: in the case of a forced shutdown, all processes will be terminated using theKill
method from thegen.Node
interface, without waiting for their graceful shutdown.
If you call the Stop
method of the gen.Node
interface from a running process (for example, within the HandleMessage
callback of your actor), this will create a deadlock. The process will remain in the running state and will be unable to terminate, while the Stop
method will wait for all processes to stop before shutting down the node.
To avoid this issue, you should either invoke the Stop
method in a separate goroutine or use the StopForce
method of the gen.Node
interface to stop the node from within a process.
Last updated