Introduction
The Event Service is a crucial component of the OpenClovis Communication Infrastructure, designed to facilitate efficient and flexible multipoint communication in distributed systems. This article will explore the key features, architecture, and operational flow of the Event Service.
What is the Event Service?
The Event Service is a publish/subscribe multipoint-to-multipoint communication mechanism that is based on the concept of event channels, where a publisher communicates asynchronously through events with one or more subscribers over an event channel.
Key Terminology
- Event: Represents any piece of data that needs to be communicated, typically related to actions or problems within the system.
- Publisher: An entity that generates and sends events.
- Subscriber: An entity that receives and processes events.
- Event Channel: A global or local communication channel that allows communication between publishers and subscribers.
- Event Data: Zero or more bytes of payload associated with an event.
- Event Attributes: The publisher can associate a set of attributes with each event such as the event pattern, publisher name, publish time, retention time, priority, etc.
- Event Pattern: The attribute that describes the type of an event and categorizes it. This is used for filtering events.
- Event Filter: The subscribers use filters based on the patterns exposed by the publisher to choose the events of interest, ignoring the rest.
Features of the Event Service
- SAF-compliant implementation: The service adheres to the standards set by the Service Availability Forum (SAF).
- Event Channels can be local or global: The local channel is limited to a single node while a global channel spans across the nodes in the cluster.
- Multiple Subscribers and Publishers: Multiple subscribers and publishers can open the same channel. An entity can be both a publisher and a subscriber.
- Guaranteed Delivery: Events are delivered in strict order with options for guaranteed or “at most once” delivery.
- Debug Support: Offers monitoring and logging capabilities for event tracking and troubleshooting.
Architecture of the Event Service
The figure below describes the event service architecture:

The architecture of the Event Service is built upon two key components: Remote Method Dispatch (RMD) and Intelligent Object Communication (IOC). This architecture enables asynchronous communication, where publishers and subscribers do not need to be aware of each other’s existence. This is accomplished via an abstraction called an event channel. All events published to a channel go to all subscribers of the channel. To handle node specific events efficiently, a channel is categorized as below:
- Local Channels: Used for communication within a single node, providing efficient event delivery without network overhead.
- Global Channels: Facilitate communication across multiple nodes in the cluster, requiring network broadcasts for event delivery.
Operational Flow of the Event Service
The figure below describes the event service flow:

To effectively use the Event Service, both publishers and subscribers must initialize the Event Client Library. Here’s how the flow typically works:
- Initialization: Both the subscriber and publisher are required to do an Event Client Library initialization to use the Event Service.
- Channel Opening:
- The publisher opens a channel with a publish flag.
- The subscriber opens a channel with a subscribe flag.
- To both publish and subscribe to a channel, set both flags. This means that the subscriber and publisher can be the same entity.
- Event Publishing or Event Subscription:
- On the publisher side: The publisher will allocate an event and set it’s attributes such as the event pattern, publisher name, publish time, retention time, priority, etc. It optionally sets the pattern to categorize the event.
- On the subscriber side: The subscriber subscribes to a particular event using a filter that will match specific event patterns that interest that subscriber.
- Event Delivery:
- On the publisher side: The event is published on the channel, which can be either local or global. If the channel is global the event is sent to all the event servers on the cluster who in turn deliver the event to any subscribers on that node. If the channel is local the event is delivered to the subscribers who have subscribed to this event locally.
- On the subscriber side: Events are delivered to subscribers based on their filters. Local events are delivered directly, while global events are broadcast across the cluster. When successful, it can get event attributes and event data.
Event service usage example
This example illustrates how a typical subscriber and publisher were developed in a model. The below source code was developed in clCompAppMain.c for both the publisher side and the subscriber side.
- On the publisher side:
Step 1: Initialize Event Library, Open Event Channel, Create Event and Set Event Attributes
const SaEvtCallbacksT evtCallbacks =
{
NULL, /* Event open callback */
NULL /* Event delivery callback */
};
SaVersionT evtVersion = {(ClUint8T)'B', 0x1, 0x1};
rc = saEvtInitialize(&evtLibHandle, &evtCallbacks, &evtVersion);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_ERROR, "Failed to init event mechanism [0x%x]\n", rc);
return rc;
}
// Open an event channel so that we can subscribe to events on that channel
rc = saEvtChannelOpen(evtLibHandle, &evtChannelName, (SA_EVT_CHANNEL_PUBLISHER | SA_EVT_CHANNEL_CREATE),
(SaTimeT)SA_TIME_END, &evtChannelHandle);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_SEV_ERROR, "Failure opening event channel [0x%x] at %ld", rc, time(0L));
goto errorexit;
}
SaNameT publisherName;
clNameSet((ClNameT*) &publisherName,PUBLISHER_NAME);
rc = saEvtEventAllocate(evtChannelHandle, &eventHandle);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_SEV_ERROR, "Failed to allocate event [0x%x]\n", rc);
assert(0);
}
rc = saEvtEventAttributesSet(eventHandle, NULL, 1, 0, &publisherName);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_ERROR, "Failed to set event attributes [0x%x]\n",rc);
assert(0);
}
- Step 2: Publish Event
static Generator generators[] =
{
generate_time_of_day,
generate_load_average
};
(*generators[index++])(&data, &data_len);
index %= (int)(sizeof generators / sizeof generators[0]);
if (data == 0 || data_len == 0)
{
clprintf(CL_LOG_SEV_ERROR, "No event data generated.");
return CL_ERR_NO_MEMORY;
}
clprintf(CL_LOG_SEV_INFO,"Publishing Event: %.*s\n",(int)data_len, data);
rc = saEvtEventPublish(eventHandle, (void *)data, data_len, &eventId);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_SEV_ERROR,"Event publish attempt failed with error [%x]", rc);
}
2.On the subscriber side:
- Step 1: Initialize Event Library, Open Event Channel and Subscribe for an event.
const SaEvtCallbacksT evtCallbacks =
{
NULL, /* Event open callback */
compEventCallback /* Event delivery callback */
};
SaVersionT evtVersion = {(ClUint8T)'B', 0x1, 0x1};
rc = saEvtInitialize(&evtLibHandle, &evtCallbacks, &evtVersion);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_ERROR, "Failed to init event mechanism [0x%x]\n", rc);
return rc;
}
// Open an event chanel so that we can subscribe to events on that channel
rc = saEvtChannelOpen(evtLibHandle, &evtChannelName, (SA_EVT_CHANNEL_SUBSCRIBER | SA_EVT_CHANNEL_CREATE),
(SaTimeT)SA_TIME_END, &evtChannelHandle);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_SEV_ERROR, "Failure opening event channel [0x%x] at %ld", rc, time(0L));
goto errorexit;
}
rc = saEvtEventSubscribe(evtChannelHandle, NULL, 1);
if (rc != SA_AIS_OK)
{
clprintf(CL_LOG_SEV_ERROR, "Failed to subscribe to event channel [0x%x]",rc);
goto errorexit;
}
- Step 2: Receive Events At callback fns.
clprintf(CL_LOG_SEV_INFO,"We've got an event to receive");
if (resTest != 0)
{
clHeapFree((char *)resTest);
resTest = 0;
}
resTest = clHeapAllocate(eventDataSize + 1);
if (resTest == 0)
{
clprintf(CL_LOG_SEV_ERROR, "Failed to allocate space for event");
return;
}
rc = saEvtEventDataGet(eventHandle, resTest, &eventDataSize);
if (rc!= SA_AIS_OK)
{
clprintf(CL_LOG_SEV_ERROR, "Failed to get event data [0x%x]",rc);
return;
}
*(((char *)resTest) + eventDataSize) = 0;
clprintf(CL_LOG_SEV_INFO,"received event: %s", (char *)resTest);
3. Result:
When the publisher publishes an event data, the subscriber will receive and extract that data correctly.
- On the publisher side:
Thu Dec 12 17:41:54.601 2024 (SCNodeI0.46164 : CompPublish_EO.---.---.00012 : INFO) compPublish: ACTIVE state requested; activating service
Thu Dec 12 17:41:54.601 2024 (SCNodeI0.46164 : CompPublish_EO.---.---.00013 : INFO) Publishing Event: Thu Dec 12 17:41:54 2024
Thu Dec 12 17:42:14.605 2024 (SCNodeI0.46164 : CompPublish_EO.---.---.00014 : INFO) Publishing Event: 0.78 0.42 0.25
- On the subscriber side:
Thu Dec 12 17:41:19.507 2024 (SCNodeI0.46112 : CompSubscribe_EO.---.---.00012 : INFO) compSubscribe: ACTIVE state requested; activating service
Thu Dec 12 17:41:54.602 2024 (SCNodeI0.46112 : CompSubscribe_EO.---.---.00013 : INFO) We've got an event to receive
Thu Dec 12 17:41:54.602 2024 (SCNodeI0.46112 : CompSubscribe_EO.---.---.00014 : INFO) received event: Thu Dec 12 17:41:54 2024
Thu Dec 12 17:42:14.605 2024 (SCNodeI0.46112 : CompSubscribe_EO.---.---.00015 : INFO) We've got an event to receive
Thu Dec 12 17:42:14.605 2024 (SCNodeI0.46112 : CompSubscribe_EO.---.---.00016 : INFO) received event: 0.78 0.42 0.25
If you want to see the full source code please refer to: Publisher and Subscriber.
Conclusion
The Event Service in OpenClovis provides a robust and flexible mechanism for communication in distributed systems. The OpenClovis also provides full APIs, so organizations can easily integrate without any difficulty.
