Table Of Contents

Previous topic

4.1. Overview

Next topic

4.3. Agent Interface Definition

This Page

4.2. Interface

In the original version of SEER, agents ran as pieces of python code with callbacks all within the same thread. In MAGI, each agent runs in its own thread or process that is started by a node daemon. When adding an agent, you are free to chose your method.

Process (Pipe or Socket)
  • Pro: Agents can be written in languages other than python
  • Pro: Can kill off agent individually from the shell
  • Con: Heavier weight if invoking a new interpreter for each agent for scripted languages
  • Con: Message transceiver is more complex, in particular if a library for the language has not been written
Threads
  • Pro: Lightweight
  • Pro: Messages passed as objects without need for serialization
  • Must be written in python
  • Con: Must be aware of other threads when it comes to file descriptors or other shared memory

4.2.1. Thread Interface

The source object provided is interpreted as python code and the daemon will search for the function getAgent in the provided code. If not found, execution fails. If found, a new thread is created and the object returned from getAgent is used. At load time, the run method on the returned object is called as run(messenger, args) and is expected not to return until the agent is done or is asked to stop. The arguments are:

  1. A magi.daemon.daemon.MessagingWrapper object for sending and receiving messages as well as the dock assigned to the agent
  2. The args list from the exec call as an array

When the agent is to be unloaded, the object method stop is called with no arguments. It is expected that the run method should eventually finish after the stop method has been called.

The messagaing wrapper interface:

def joinGroup(self, group): pass
def leaveGroup(self, group): pass

def listenDock(self, dock): pass
def unlistenDOck(self, dock): pass

def send(self, msg, args=None): pass
def next(self, block=True, timeout=None): pass

Example Strawman agent:

class MyAgent(object):

     def run(self, messenger, args):
         """ This is called when its time to start in the agents own thread """
         pass

     def stop(self):
         """ This is called when its time to stop, probably use a flag variable to indicate time to stop """
         pass

def getAgent():
     return MyAgent()

4.2.2. Process Interface - Socket

Process Value
argv[0] name
argv[1] assigned dock
argv[2..] args passed in message to exec agent

Processes are started with the arguments specified in the Exec message. There will be a localhost only server running on port 18809. This server stream acts the same as the stdin/stdout of the pipe interface. The socket interface is also the method for scripts to connect to the daemon process.

4.2.3. Process Interface - Pipe

Process Value
argv[0] name
argv[1] assigned dock
argv[2..] args passed in message to exec agent
stdin pipe with incoming serialized messages
stdout pipe for outgoing serialized messages
stderr tempfile

Processes are started with stdin as a source of messages, stdout as a path for outgoing messages and stderr will be captured in a tempfile that can be sent or queried. The arguments to the process can be specified in the Exec message. The setup is effectively the same as the socket interface with stdin/stdout replacing a TCP socket.

4.2.4. Process Interface - Encoding

We make use of the same code that perform messaging passing for stream based messaging in the transmission of data to agents running as processes. For this reason, the encoding of messages across the stream look very similar. Libraries will be provided in Python, Perl and C.

PREAMBLE TotalLen HeaderLen [Header] [Data]

Header Format
Content Size Description
Length 4 bytes header + data not including 4 length bytes
Header Length 2 bytes length of just the header not including this length value
Type 1 byte The agent process request
Headers variable type-length-value options (byte, byte, variable)
Data variable the actual message data

Types
Name Code Description
Join Group 1 Request for the node to join a group, the value is in the data portion
Leave Group 2 Request for the node to leave a group, the value is in the data portion
Listen Dock 3 Request that messages for dock are delivered to this agent, value in data
Unlisten Dock 4 Request to stop delivering dock messages to this agent, value in data
Message 5 Send/Receive a message, encoded MAGIMessage in data, header contains delivery requests for sending

Possible Header Options
Name Code Description
Acknowldgement 1 Request that the message is acknowledgement or restransmission occurs, no value
Source Ordering 2 Request that message is delivered in order as sent by this host, no value
Timestamp 3 Request that message is delivered on or after the given timestamp, expects 4 byte time value

4.2.4.1. Message Send Example

This is an example of sending a message from the agent to the daemon requesting source ordering and timestamp processing for the message.

Field Data
Preamble MAGI[0x88]PKT
Length 1234
HeaderLength 9
Type 5 (Send Message)
Request 1 2, 0 (Source Ordering)
Request 2 3, 4, 1234567 (Timestamp)
Data Encoded MAGI Message (See Wire Formats)

Encoding
1 2 3 4 5 6 7 8 9 10 11 12
MAGI[0x88]PKT 1234
9 5 2 0 3 4 1234567 ...
1223 bytes of encoded MAGI Message

4.2.4.2. Join Group Example

This is an example of the agent requesting that the daemon join the messaging group MyGroup.

Field Data
Preamble MAGI[0x88]PKT
Length 9
HeaderLength 1
Type 1 (Join Group)
Data “MyGroup”

Encoding
1 2 3 4 5 6 7 8 9 10 11 12
MAGI[0x88]PKT 9
1 1 “MyGroup” —-