Event Service¶
The RTC Toolkit provides an Event Service library that enables RTC Components to publish and
subscribe customisable events over the non-deterministic control network (CND). The Event Service
is based on CII MAL using FastDDS. It makes use of the pre-defined MAL topic type
rtctkif::GenericEvent
that carries a BLOB
with a customisable JSON
payload.
Design Assumptions¶
The event service is used to exchange notification events within the SRTC via a publish and subscribe messaging pattern. Events should be rather small (few KB) and they should be emitted at relatively low rates (up to 1 Hz).
Main event sources are Data Tasks and HRTC Supervisors. Such components emit events e.g. after performing computations or when applying new configurations to the HRTC.
Main event sinks are GUIs, Telemetry Recorders, Metadata Collectors as well as Data Tasks and HRTC Supervisors. While GUIs visualise emitted events (e.g. in an event screen), Recorders and Collectors dump interesting events to FITS files. Data Tasks and HRTC Supervisors ‘react’ on events (e.g. start computations or apply configurations to the HRTC).
To provide enough flexibility the Event Services comes with two APIs: a low-level API and a high-level API. While the low-level API allows publishing and subscribing JSON objects on specified topic names, the high-level API is aware of different event types. Additionally, a set of common event types are already defined and they can be further customised by instrument RTC developers in order to create a hierarchy of event types.
Low-level API¶
To use the low-level event service include the follow header:
#include <rtctk/componentFramework/eventServiceIf.hpp>
The low-level event service object can be retrieved from the service container using:
EventServiceIf& es = services.Get<EventServiceIf>();
To publish low-level events use:
JsonPayload payload = {
{"origin", "data_task_1"},
{"time", 12345628652},
{"type", "computation_event"},
{"item", "control_matrix_foo"},
{"result", 42},
};
auto pub = es.MakePublisher("computation_topic");
pub->Publish(payload);
To subscribe to low-level events use:
auto sub = es.MakeSubscriber("computation_topic");
sub->Subscribe("computation_topic",
[](JsonPayload const& payload) {
std::cout << payload.dump() << std::endl;;
});
// ...
sub->Unsubscribe();
High-level API¶
To use the high-level event service include the follow header:
#include <rtctk/componentFramework/typedEventService.hpp>
The high-level event service object can be constructed with the low-level event service using:
TypedEventService tes{services.Get<EventServiceIf>()};
To publish high-level events use:
auto pub = tes.MakePublisher<ComputationStartedEvent>();
pub->Publish({"data_task_1", "control_matrix_foo"});
To subscribe to high-level events use:
auto sub = tes.MakeSubscriber<ComputationStartedEvent>();
sub->Subscribe<ComputationStartedEvent>(
[](ComputationStartedEvent const& ev) {
std::cout << ev.ToJson().dump() << std::endl;;
});
// ...
sub->Unsubscribe();
Predefined Event Types¶
The high-level API comes with a set of predefined event types:
Event Type |
Topic Name |
Description |
---|---|---|
AbstractEvent |
none |
abstract, common base for all event types |
ComputationEvent |
computation_topic |
abstract, defines common event attributes |
ComputationStartedEvent |
computation_topic |
signals that computation has started |
ComputationFinishedEvent |
computation_topic |
signals that computation has finished |
ConfigurationEvent |
configuration_topic |
abstract, defines common event attributes |
ConfigurationUpdatedEvent |
configuration_topic |
signals that a configuration item was updated |
ConfigurationRetrievedEvent |
configuration_topic |
signals that a configuration item was retrieved |
HrtcConfigurationScheduledEvent |
configuration_topic |
signals that a configuration item was scheduled to be applied in HRTC |
HrtcConfigurationAppliedEvent |
configuration_topic |
signals that a configuration item was applied in HRTC |
CoordinationEvent |
coordination_topic |
abstract, defines common event attributes |
StateChangedEvent |
coordination_topic |
signals that an entity changed its state |
HrtcStateChangedEvent |
coordination_topic |
signals that an entity in HRTC changed its state |
AlertStatusEvent |
alert_status_topic |
event published when alert status is changed |
The general idea is that instrument RTC teams use these event types as-is or specialise them according to their needs.
Creating Custom Event Types¶
Custom event types can be created by specialising toolkit-provided event types.
struct CustomComputationEvent : ComputationEvent
{
CustomComputationEvent(std::string origin, std::string item, int attribute)
: ComputationEvent(origin, item)
, custom_attribute(attribute)
{ }
CustomComputationEvent(JsonPayload const& payload)
: ComputationEvent(payload)
, custom_attribute(payload["custom_attribute"])
{ }
JsonPayload ToJson() const {
auto payload = ComputationEvent::ToJson();
payload["type"].push_back(PrettyTypeName<CustomComputationEvent>);
payload["custom_attribute"] = custom_attribute;
return payload;
}
int custom_attribute;
// optional: override the topic_name of the parent event type
// inline static const std::string topic_name = "test_topic";
};
In the example above, the event type CustomComputationEvent
is defined by extending
toolkit-provided event type ComputationEvent
event with additional attribute custom_attribte
.
For serialisation and deserialisation purpose a constructor taking a JsonPayload and method ToJson
need to be implemented. Additionally, constructors to create new events from required input data
need to be defined as well.
Note that the high-level API allows to publish specialised events like CustomComputationEvent
and subscribe to them using the base event type e.g. ComputationEvent
, but this is only
possible if the same topic name is used.
Limitations and Known Issues¶
While the low-level API is more flexible, the high-level API is more compact and simpler to use. It is recommended not to mix both API types within the same component.
Do not subscribe or unsubscribe events from within the subscription callback, this causes deadlocks!