Cyclus Server (cyclus.server)

An asyncronous cyclus server that provides as JSON API over websockets.

The webserver has a number of ‘events’ that it may send or recieve. These in turn affect how a cyclus simulation runs.

The server, which operates both asynchronously and in parallel, has five top-level tasks which it manages:

  • The cyclus simulation object, run on a separate thread,
  • A action consumer, which executes actions that have been queued either by the cyclus simulation or the user,
  • A websockets server that sends and recieves JSON-formatted events from the client.
  • A heartbeat that sends special events every so often.
  • A monitor for presenting data about certain other future actions.

For purposes of this document, the following terminology is used:

event: A JSON object / dictionary that contains behaviour instructions.

message: The string form of an event.

action: A delayed asynchronous coroutine function that carries out the behaviour specified in a cooresponding event. These do the actual work of the event system.

repeating action: An action coroutine function (or event name) or a list of the coroutine function and arguments that is added to the action queue each time step of the simulation. This enables pausing each time step, streaming table data, etc.

task: A future object that results from calling an action. See asyncio for more details.

Events

Events are JSON-formatted strings that represent JSON-objects (dicts) at their top-most level. All events must have an “event” key whose value is the string name that distinguishes the event from all other kinds of events.

Often times, events may have parameters that they send/recieve. These live in the “params” key as a JSON object / dict.

Events may be conceptually divided into server-sent, client-sent events, and bidirectional events which are sent by either the client or the server.

Server Events

Server-sent events are those that the server sends to the client. These are often repsonse to requests for data about the state of the simulation. They typically contain a “data” key which holds data about the simulation state. They may also have a “success” key, whose value is true/false, that specifies whether the data was able to be computed.

heartbeat: A simple event the lets the client know that the server is still alive. The data value is the approximate time of the next heartbeat in seconds:

{"event": "heartbeat", "data": val}

loaded: A simple message that says that a simulation has been loaded.

{“event”: “loaded”,
“params”: {“status”: “ok”}, “data”: null

}

registry: The in-memory backend registy value in its current form:

{"event": "registry",
 "params": null,
 "data": ["table0", "table1", ...]
}

table_names: The current file system backend table names:

{"event": "table_names",
 "params": null,
 "data": ["table0", "table1", ...]
}

Client Events

Client events are often requests originating from users. They may either express a request for behaviour (pause the simulation, restart, etc.) or a request for data. These events may or may not have additional parameters, depending on the type of request.

deregister_tables: Remove table names from the in-memory backend registry. A registry event from the server will follow the completion of this event:

{"event": "deregister_tables",
 "params": {"tables": ["table0", "table1", ...]}
 }

load: Loads the input file in the simulation and starts running the simulation:

{"event": "load"}

pause: Pauses the simulation until it is unpaused:

{"event": "pause"}

register_tables: Add table names to the in-memory backend registry. A registry event from the server will follow the completion of this event:

{"event": "register_tables",
 "params": {"tables": ["table0", "table1", ...]}
 }

registry_request: A simple reqest for the in-memory backend regsitry:

{"event": "registry_request"}

shutdown: A reqest to shutdown the server:

{"event": "shutdown",
 "params": {"when": "empty" or "now"}
 }

table_names_request: A simple reqest for the table names present in the file system backend:

{"event": "table_names_request"}

unpause: Unpauses the simulation by canceling the pause task:

{"event": "unpause"}

Bidirectional Events

These are events that may logically originate from either the client or the server. Certian keys in the event may or not be present depending on the sender, but the event name stays the same.

agent_annotations: This event requests and returns the agent annotations for a given agent spec. If the data field is null, this is a request to the server for annotation information. If the data field is a dict, it represents the annotations for the spec:

{"event": "agent_annotations",
 "params": {"spec": "<path>:<lib>:<name>"},
 "data": null or object
}

echo: Echos back a single string parameter. When requesting an echo, the data key need not be present:

{"event": "table_names",
 "params": {"s": value},
 "data": value
}

sleep: The requester instructs the reciever to sleep for n seconds:

{"event": "sleep", "params": {"n": value}}

table_data: Data about a table with the conditions and other parameters applied. If the client sends this event without the “data” key, the server will respond with the requested table:

{"event": "table_data",
 "params": {"table": "<name of table>",
            "conds": ["<list of condition lists, if any>"],
            "orient": "<orientation of JSON, see Pandas>"},
 "data": {"<keys>": "<values subject to orientation>"}
}

Command Line Interface

You may launch the cyclus server by running:

$ python -m cyclus.server input.xml

Most of the arguments are relatively self-explanatory. However, the CLI here also allows you to load initial and repeating actions. The syntax for this is an event name followed by parameter tokens (which must contain an equals sign):

$ python -m cyclus.server input.xml --repeating-actions sleep n=1

You may load many actions by repeating the name-params pattern:

$ python -m cyclus.server input.xml –repeating-actions sleep n=1 table_data table=”TimeSeriesPower”

Note that everything right of an equals sign in a parameter token is passed to Python’s eval() builtin function. It thererfore must be valid Python. For string values, make sure that you properly escape quotation marks as per the syntax of your shell language.

class cyclus.server.EventCLIAction(option_strings, dest, nargs='+', **kwargs)

A basic class for parsing action specs on the command line.

cyclus.server.action_consumer(state)

The basic consumer of actions.

cyclus.server.action_monitor(state)

Consumes actions that have been scheduled for monitoring tasks, such as status reporting, sending signals, or canceling other task. These are awaited in the order recieved.

cyclus.server.get_send_data()

Asynchronously grabs the next data to send from the queue.

cyclus.server.heartbeat(state)

This sends a heartbeat event to the client with a nominal period. This occurs outside of the normal action-consumer event system. The client is then able to detect the lack of a heartbeat and know that the server has been disconected.

cyclus.server.main(args=None)

Main cyclus server entry point.

cyclus.server.make_parser()

Makes the argument parser for the cyclus server.

cyclus.server.queue_message_action(message)
cyclus.server.run_sim(state, loop, executor)

Runs a cyclus simulation in an executor, which should be on another thread.

cyclus.server.websocket_handler(websocket, path)

Sends and recieves data via a websocket.