Network - MRHS/APrime GitHub Wiki
APrime uses multicast to broadcast messages to multiple nodes at once when used on an internal network. Any node can create tasks (in our case, initial numbers) that can be processed by others nodes.
Joining
Joining should be as simple as connecting to the multicast socket and announcing that you have arrived, just like it should be done elsewhere.
The joining node would simply need to send a JOINED
message, which notifies all other nodes that it has joined.
JOINED
All other nodes should then add the IP to a local registry.
In addition, we should add an acknowledgement message of sorts that contains the number of nodes that are in the cluster. This way, since there is no actual guarantee that the multicast packet will reach all the available nodes, we can keep sending multicast packets until we've contacted all of the nodes. In addition, each node should only ever acknowledge a new node once to ensure things don't get all funky.
ACK <number of available nodes in cluster>
The node joining the cluster should open up a TCP socket for every node that replies to the JOINED
message, and the acknowledgement should be send via the respective TCP socket (to ensure that we don't get the wrong number of nodes and break everything). An alternative to using the TCP socket method would just be to also include a CRC checksum with every UDP packet, and request a resend to any nodes that send bad packets.
Leaving
In the event that a node knows that it will have to leave (and it is not unexpected), the node should notify all other nodes.
The leaving node should iterate through it's list of known nodes and send a LEAVING
message to each node.
LEAVING
All other nodes should then remove the IP from their table of known nodes.
Pinging
Because it is impossible to know what other nodes are attached to a socket, nodes should ping each other every few minutes.
The initial node should iterate through all of the known nodes with PING
through their respective sockets.
PING
All other nodes should reply with a PONG
message, which allows those listening to the socket to rebuild their internal registries. Nodes which do not respond to a ping should be considered unreachable after a specified timeout.
PONG
In the event that the network becomes crowded, a separate socket should be created on the primary node and the PONG
messages should be sent directly to that node.
(Chandler: I don't really know if this would actually become an issue, with the design it looks like we're leaning toward the data being sent to each node should be rather minimal)
Tasks
APrime depends on individual tasks to be created which are distributed throughout the nodes. All tasks have a unique ID and task status that is associated with them.
All task information should be sent using TASK
messages:
TASK [id] [status]
Task status
Each task should have a status attached to it.
- New - The task was just created
- Started - The task has been started and does not need any more nodes to handle it.
- Aborted - The task generated an error and had to be aborted.
- Finished - The task finished.
New tasks
New tasks should be broadcast from one node to all of the other node's respective TCP sockets. The only information they should carry is a unique task ID and the socket which the rest of the information will be broadcast on. The creators of the task are responsible for distributing the task information.
The initial creation message should be a TASK
message.
TASK [id] 1 [socket]
Nodes interested in taking the task should connect to the sender on the specified socket via TCP. It is up to the sender to determine how many nodes should be able to handle a task. Tasks are sent as serialized Task
objects via an Object[Input/Output]Stream
.
Important: New task notices should be limited once nodes stop responding in a timely manner. The exact time is up to the sender, but tasks should not be created twice as fast as they are being completed.
Task started
When a task is marked as started, the socket which was created for distributing the task should be closed. At this point, no other nodes should attempt to take the task.
TASK [id] 2
Task aborted
In the event that the task generates an error, a notification should be broadcasted which notifies all nodes of the issue.
TASK [id] 3
Task finished
When a task finishes, the carrying node should broadcast over the network that the task has been completed. A socket should be opened which allows a TaskResult
to be taken by anyone who is interested in the result.
TASK [id] 4 [socket]
Nodes interested in receiving the result should connect to the sender on the specified socket via TCP. The result would then be distributed through serialized TaskResult
objects using an Object[Input/Output]Stream
.