Closed thomasthebaker closed 6 years ago
Hi Tom,
please take a look at the NiProvider example example360MarketPriceConnectionRecovery. I have run the example with the ADH and ETA consumer example. I have bounced the ADH and my consumer example starts getting the updates after the ADH comes back up.
Hi seba5, Thanks for your pointer. I got the example working and it's fine, just as you described. I then dug a bit deeper into our own application that wasn't working. I've found the reason why the subscription streams do not recover after the NI Provider reconnects. The Directory message that is sent by the Elektron components (I think a cached version of the user's original Directory message) changes the service ID. The ADH reports the connection up event with a different service ID. If I set the service ID to '0' to match the behaviour of the retransmitted directory message then the subscription stream recovers.
I am not using XML to configure the service as I want to switch the service name at run time. Perhaps this is a bug with the connection recovery feature in Elektron, should it preserve the Service ID that the user originally sets? Do you know the relevance of the ServiceID outside of a single NI Provider application? It obviously has an effect on the subscription streams.
Here's our configuration code. It's the SERVICE_KEY value that get's ignored by Elektron on connection recovery:
/**
* Builds an MMT_DIRECTORY RefreshMsg used to register service information with an ADH when logging in.
* @param publishServiceName the name of the service that will be published (e.g. STAT, EXT2...)
* @return a fully populated RefreshMsg that can be used to perform directory registration with an ADH server.
*/
private static RefreshMsg buildDirectoryMessage(String publishServiceName) {
OmmArray capablities = EmaFactory.createOmmArray();
capablities.add(EmaFactory.createOmmArrayEntry().uintValue( EmaRdm.MMT_MARKET_PRICE));
OmmArray dictionaryUsed = EmaFactory.createOmmArray();
dictionaryUsed.add(EmaFactory.createOmmArrayEntry().ascii(DictionaryClient.DictionaryType.RWFFld.name()));
dictionaryUsed.add(EmaFactory.createOmmArrayEntry().ascii(DictionaryClient.DictionaryType.RWFEnum.name()));
ElementList serviceInfoId = EmaFactory.createElementList();
serviceInfoId.add(EmaFactory.createElementEntry().ascii(EmaRdm.ENAME_NAME, publishServiceName));
serviceInfoId.add(EmaFactory.createElementEntry().uintValue(EmaRdm.ENAME_IS_SOURCE, 0)); // service is consolidation of multiple sources into a single service. Affects connection recovery on outage.
serviceInfoId.add(EmaFactory.createElementEntry().uintValue(EmaRdm.ENAME_ACCEPTING_CONS_STATUS, 0)); // We do not process ADH messages relating to Hot/Standby status
serviceInfoId.add(EmaFactory.createElementEntry().uintValue(EmaRdm.ENAME_SUPPS_OOB_SNAPSHOTS, 0)); // Not supported
serviceInfoId.add(EmaFactory.createElementEntry().uintValue(EmaRdm.ENAME_SUPPS_QOS_RANGE, 0)); // Not supported
serviceInfoId.add(EmaFactory.createElementEntry().array(EmaRdm.ENAME_CAPABILITIES, capablities));
serviceInfoId.add(EmaFactory.createElementEntry().array(EmaRdm.ENAME_DICTIONARYS_USED, dictionaryUsed));
ElementList serviceStateId = EmaFactory.createElementList();
serviceStateId.add( EmaFactory.createElementEntry().uintValue(EmaRdm.ENAME_SVC_STATE, EmaRdm.SERVICE_UP));
// indicate that we can handle reissue on existing streams. Helpful on service outage.
serviceStateId.add( EmaFactory.createElementEntry().uintValue(EmaRdm.ENAME_ACCEPTING_REQS, 1));
// state to send to existing streams
serviceStateId.add( EmaFactory.createElementEntry()
.state("Status", OmmState.StreamState.OPEN, OmmState.DataState.OK, OmmState.StatusCode.NONE, "OK"));
FilterList filterList = EmaFactory.createFilterList();
filterList.add(EmaFactory.createFilterEntry().elementList(EmaRdm.SERVICE_INFO_ID, FilterEntry.FilterAction.SET, serviceInfoId) );
filterList.add(EmaFactory.createFilterEntry().elementList(EmaRdm.SERVICE_STATE_ID, FilterEntry.FilterAction.SET, serviceStateId));
Map map = EmaFactory.createMap();
map.add( EmaFactory.createMapEntry().keyUInt(SERVICE_KEY, MapEntry.MapAction.ADD, filterList));
return EmaFactory.createRefreshMsg()
.domainType(EmaRdm.MMT_DIRECTORY)
.filter(EmaRdm.SERVICE_INFO_FILTER | EmaRdm.SERVICE_STATE_FILTER)
.payload(map);
}
If I just pause the VM for 30s then the ADH logs the following information that shows the service ID is being changed:
<rmds.1.adh.sourceSSLDistribution.sslDispatcher.EXT2: Info: Thu Aug 17 17:37:00 2017>
Server "EXT2" started for RSSL application "EXT2:1" from instance "FOO.26". The application sent a service up state.
<rmds.1.adh.sourceSSLDistribution.sslDispatcher.EXT2: Info: Thu Aug 17 17:37:50 2017>
Server "EXT2" stopped for RSSL application "EXT2:1" from instance "FOO.26". The application terminated the session.
<rmds.1.adh.sourceSSLDistribution.sslDispatcher.EXT2: Info: Thu Aug 17 17:37:56 2017>
Server "EXT2" started for RSSL application "EXT2:0" from instance "FOO.28". The application sent a service up state.
Tom, thank you for providing more details. It looks like this is a known issue. During the connection recovery we are sending a Source Directory message with serviceId of 0. There is a workaround. You can modify your application to resend the Source Directory message once the connection comes up again. Please let me know if that helps, thank you.
It's all working if I always set the serviceId to 0. I'm not sure on the significance of the serviceId and how it should be set? The example application uses a serviceID of '11', is there any particular reason? I couldn't find anything specific in the documentation.
Tom, serviceId needs to be unique. It is linked to the service name. If your application is only publishing one service you can use the serviceId set to 0. The application used a service Id of 11 to show that it can be something other than 0. 11 is not a special number. Let me know if this answers your question. Thanks.
I have been running a few tests and I'm having trouble with the resiliency of the OmmNiProvider. It appears from the logs that after a connection failure, everything recovers nicely and the reactor channel underneath is being dispatched again. However, any subscription clients do not see the messages that are sent after a network failure. Here are the steps:
The adh seems to recognise that the application is active again after the outage:
The logs from the Reactor channel appear to show that everything has been setup correctly for the recovery:
Given the OmmNiProvider has logged in again and send the Directory messages, should I expect the provider to be fully functional after an outage like this? At the moment I will have to uninitialise the original Provider and instantiate a new one to work around this issue.
Have I missed some configuration somewhere?