Server Communication - Pyosch/powertac-server GitHub Wiki
up
As of 2011-02016, this area is under discussion and subject to change. Please see the Nabble discussion on this topic for an updated view.
The Power TAC competition is designed as a clock driven, competitive simulation. Two kinds of events drive activity:
- One is the passage of time -- the simulation clock (org.powertac.common.TimeService) maintains a queue of "actions" that will be triggered at specific times. Any object can post an action to be triggered in the future, and actions can re-enter themselves in the queue for later times, leading to repeating events. This type of activity is, of course, restricted to a single process context.
- The other is message arrival, where the activity of one actor (say Broker Bob) results in a message being created and sent, which may be received by other entities (say a response of one of Broker Bob's customers) who may then act on the received message. This is the mechanism by which distributed portions of the system interact (Brokers and the Server, for example).
There are four kinds of communication in the system:
Within the server, communication is by method call. In order to reduce coupling, much of this is done using variations on the Observer pattern. For example, a module may register with the TariffMarket
to receive new tariff publications. In some cases, communication happens simply by having one module make entries in the database and another make queries of the database. This is how the current set of enabled timeslots is communicated.
Between the broker and server, communication is by serialized objects over JMS, using Apache MQ. On the server side, these channels are encapsulated in the BrokerProxyService
. To send messages to a broker, a server module calls sendMessage(broker, msg)
, and to broadcast a message to all brokers, a server module calls broadcastMessage(msg)
.
All message types must be serializable using XStream, but should not implement the Serializable
interface. To use XStream effectively, classes should be annotated in a way that controls the depth of serialization. An example is TariffSpecification
, for which serialization sucks in all its attached Rates
and their HourlyCharge
instances, but includes only the id field of its attached Broker
instance.
Inside the BrokerProxyService
, message objects (or lists of objects) are serialized into xml, wrapped with JMS headers, and queued for broker delivery by Apache MQ.
From the standpoint of a server module, incoming messages from brokers arrive in the BrokerProxyService, are deserialized and stored in the database, and finally dispatched to registered listener modules. Incoming messages are classified into two groups: tariff messages and market messages. To receive tariff messages, a module may register itself by calling brokerProxyService.registerBrokerTariffListener(listener)
, and to receive incoming market messages, a module may register itself with brokerProxyService.registerBrokerMarketListener(listener)
.
The visualizer receives copies of all messages sent to or received from brokers. Is this enough?
Here is the original server communication scheme, now obsolete.