Detailed usage¶
Gracefully exit module instances¶
The process in which the Agent stops a module is not trivial.
The EVP Agent first needs to set a status on the module instance
that it needs to exit.
After some amount of time,
if the module did not exit gracefully
(by calling exit(3)
or returning from main
),
the agent will forcefully stop and kill the module.
This is implemented within the module instance “supervisor”.
All events in a module instance are processed by EVP_processEvent()
.
If the agent wants the module instance to exit,
EVP_processEvent()
would still dispatch any pending events.
The agent would then notify the module via the event callback
when an event is generated by:
EVP_sendState()
would haveEVP_STATE_CALLBACK_REASON_EXIT
as itsreason
on the event callback.EVP_sendTelemetry()
would haveEVP_TELEMETRY_CALLBACK_REASON_EXIT
as itsreason
on the event callback.EVP_sendMessage()
would haveEVP_MESSAGE_SENT_CALLBACK_REASON_EXIT
as itsreason
on the event callback.EVP_sendRpcResponse()
would haveEVP_RPC_RESPONSE_CALLBACK_REASON_EXIT
as itsreason
on the event callback.EVP_blobOperation()
would haveEVP_BLOB_CALLBACK_REASON_EXIT
as itsreason
on the event callback.
EVP_processEvent()
would still return EVP_SHOULD_EXIT
only if there are no more events pending on the input queue to the module.
When any of the *_REASON_EXIT
error codes is received,
the module instance must stop generating any new events,
and keep calling EVP_processEvent()
until EVP_SHOULD_EXIT
is returned.
This is done for the module to be able to process all the pending events
before it actually exits.
Some examples of functions that generate events are
EVP_sendState()
, EVP_sendTelemetry()
and EVP_sendMessage()
.
Sample module¶
A correct implementation of the module would be (includes and some details are omitted for clarity):
static int stopping = 0;
static void
telemetry_cb(EVP_TELEMETRY_CALLBACK_REASON reason, void *userData)
{
static int counter = 0;
if (reason == EVP_TELEMETRY_CALLBACK_REASON_EXIT) {
stopping = 1;
printf("Telemetry not sent, the module was requested to stop.\n");
}
else {
printf("Telemetry sent %d\n", counter++);
}
}
int main() {
struct EVP_telemetry_entry entries[1];
entries.key = "myKey";
entries.value = "myValue";
struct EVP_client *h = EVP_initialize();
for(;;) {
// Don't add more event if the module is stopping
if (!stopping) {
EVP_sendTelemetry(h, entries, 1, telemetry_callback, NULL);
}
int ret = EVP_processEvent(h, 1000);
if (ret == EVP_SHOULD_EXIT) {
break;
}
}
return 0;
}
When the module instance is requested to stop,
EVP_TELEMETRY_CALLBACK_REASON_EXIT
is signalled by telemetry_cb
,
so that the module instance does not call EVP_sendTelemetry()
anymore.
Then,
the module instance flushes all the events in the queue,
until EVP_processEvent()
returns EVP_SHOULD_EXIT
,
so the module instance break``s
and finally ``return``s from ``main
.