question

Upvotes
Accepted
124 0 1 0

Does completion event available in Login stream?

According to the DeveloperGuide 10.1.6.3 - Event Handler Restrictions,

The multi-threaded application must use completion events. The application should cancel all currently activerequests that were made with the instance of the client specified and wait for a completion event for each of thoserequests. While waiting for a completion event, an application might receive other events that close the stream(e.g. a status message that closes the stream) before the completion event arrives.
Whenever the isEventStreamClosed() function returns true (for either a completion event or some other streamclosing event), the application can delete the client instance.

Since I cannot see the completion event in my test, I am wondering if the above statement also apply to login stream?



treprfarfa-apilog-in
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
Accepted
28.3k 30 11 15

@kc.lam,

Going back to your questions.

Not at all. Getting a simple RFA C++ example or one of our tutorials to print streaming prices is quick and easy, but to design a production strength app- takes thought, time and effort.

In that line of thought, in my opinion, this will not be sufficient. If planning to stay with RFA C++, would do 2 things:

Review RFA Developer guide for threading tips. It discusses all things one should avoid doing with threaded apps, as well as best practices. See "Event Distribution Usage Guidelines" and "Cleaning up". RFA will attempt, on destroy, to cleanup everything properly on behalf of the app, however, the best practice is to try to "for the application to clean up any resources that it has created, registered for, or acquired". In the order that is opposite to that of initialization.

Take a simple example, StarterConsumer that came with SDK is very popular and do full cleanup properly, observing and printing events and steps. Then integrate the same cleanup sequence into your custom app.

For example:

Print completion events separately to be more visible

void StarterConsumer::processEvent(const Event& event)
{

    switch(event.getType())
    {
        case ConnectionEventEnum:
            processConnectionEvent(static_cast<const ConnectionEvent&>(event));
            break;
        case OMMItemEventEnum:
            processOMMItemEvent(static_cast<const OMMItemEvent&>(event));
            break;
        case OMMCmdErrorEventEnum:
            processOMMCmdErrorEvent(static_cast<const OMMCmdErrorEvent&>(event));
            break;
        case LoggerNotifyEventEnum:
            processLoggerNotifyEvent(static_cast<const LoggerNotifyEvent&>(event));
            break;
        case rfa::common::ComplEventEnum:
            AppUtil::log(__LINE__, AppUtil::WARN, "****** Receive Completion Event"
 ...

Register to receive completions per all streams

_pOMMConsumer = _pSession->createOMMConsumer(RFA_String(_appName, 0, false),true);

And modify cleanup per prod requirements. Test and observe, tune per your needs. Examples were written for simplicity,rather then completeness that is required for production strength apps. This is still a simplification, that may be a good as a starting point:

void StarterConsumer::cleanup()
{
    AppUtil::log(__LINE__, AppUtil::TRACE, "::cleanup()");
    //    if(_pEventQueue)
    //        _pEventQueue->deactivate();  ZF
    if (_pOMMConsumer)
    {
        if (_pLoginHandle)
        {
            _pOMMConsumer->unregisterClient(_pLoginHandle);
            _pLoginHandle = 0;
        }
        if (_pOMMConnIntSpecHandle)
        {
            _pOMMConsumer->unregisterClient(_pOMMConnIntSpecHandle);
            _pOMMConnIntSpecHandle = 0;
        }
        if (_pOMMErrIntSpecHandle)
        {
            _pOMMConsumer->unregisterClient(_pOMMErrIntSpecHandle);
            _pOMMErrIntSpecHandle = 0;
        }
        _pOMMConsumer->destroy();
        _pOMMConsumer = 0;
    }
    for (int i = 0; i < 10; i++) { //ZF 
        long dispatchReturn = _pEventQueue->dispatch(10);
        Sleep(100);
    }

    if (_pEventQueue)       //ZF
        _pEventQueue->deactivate();

    if(_pSession)
    {
        _pSession->release();
        _pSession = 0;
    }
    if(_pAppLoggerMonitor && _pLoggerHandle)
    {
        _pAppLoggerMonitor->unregisterLoggerClient(_pLoggerHandle);
...

As you have processing in other threads, completions become especially important to observe prior to the next step in uninit.

Further on question 2, destroy, yes, believe you can call consumer destroy separately, from a different thread, as long as the destruction sequence required is complete and sequencing is observed. However, since this is not a single step, but a compete proper sequence of cleanup is required, it is usually run as a sequence, each step building on the previous completing successfully, not taken from a different thread.

I hope this helps

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Hi @zoya.farberov, thanks for the detailed explanation. Our application runs without using event queue, so it is pretty much the same as your example code.

Upvote
28.3k 30 11 15

Hello @kc.lam,

Apologies for the belated response.

As you mention that you can not see completion event in your test, like to ask you a couple of questions, so we may be sure to fully understand yours:

Have you tried testing with one of the standard examples that came with SDK, or this is your custom code that does not see the completion event?

If testing with one of the standard examples, out of the box they would not be receiving completions, for a couple of reasons.

I would test with one of the standard examples first, and modify, because they modify easily and concisely, and because with the custom code we cannot be sure what is happening, unless we review the custom code in-depth, and that can not be done within the framework of the discussion forums.

  • Are you registering for the completion events, when creating consumer, as default is false?
virtual OMMConsumer* rfa::sessionLayer::Session::createOMMConsumer 
(
const rfa::common::RFA_String & 
name

bool 
wCompEvents = false 

)
  • Are you keeping the event queue alive, past unregister?
  • Are you continuing to dispatch events past unregister?
  • Are you waiting some, past unregister, and prior to the rest of uninit, so you could receive the completion?

Let me know if my questions make sense, or are confusing?




icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
124 0 1 0

Hi @zoya.farberov,

Thanks for your reply, I can get the completion event after enabling it in the OMM Consumer constructor. Sorry for asking this stupid question, but now I got another question concerning the proper shutdown procedure.
We are running in single-thread callback mode. During program termination, the SIGTERM signal is caught in another thread to perform cleanup in the following sequence:

  1. Unregister the login stream, as to close al other open interests as well
  2. Destroy the OMMConsumer
  3. Release the RFA session and then un-initialize RFA context

Then my questions are:

  1. Should we wait for the completion event between step 1 and 2? In the future, we may want to change to dual-thread callback mode, would it cause any difference?
  2. I can't find the thread-safety remarks for destroy() in API manual, so in step 2), is it safe for us to call ommConsumer->destroy in another thread?

Thanks in advance!!

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
28.3k 30 11 15

Hello @kc.lam,

For a new application, I would seriously consider Elektron Suite of API over RFA C++.

At present, RFA C++ is a fully supported, feature-complete API. Elektron Message API C++ will have all the new features, and it's an actively developed, new API. It will also take significantly less time and effort for you to develop a custom consumer per requirements. If you need the low level access- Elektron Transport API can be used.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.