question

Upvotes
Accepted
23 8 12 13

Source unavailable message always popup when starting program everytime.

Client is in TREP environment , everytime when client start the program to fetch items.

The program get "Source unavailable" messages several times after the "all is well received" message received.

treprfarfa-api
unavailable.png (67.0 KiB)
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
11.3k 25 8 14
@jessie.lin

The "Source unavaiable" status generally is created by RFA to inform that the data's status is suspect because the requested service is down or unavailable and the item will be recovered when the service is up.

This log should be from the scenario that application requests item before the connection is establised so the requested service was not avialable at that time. This commonly be found in the application such as "StarterConsumer" example that request item imediately after login request without verifying service status.

With regard to the "received invalid item data from server." message, the message should not be received from API/feed. I understand that the message is the application's message. Is this correct?

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

Below is the snippet example code based on StarterConsumer to verify Service Status to solve this issue.


Step 1: Send the Directory Request after received login success response.

Handle* StarterConsumer::sendDirectoryRequest()
{
  ReqMsg reqMsg;
  AttribInfo attribInfo;
  Handle* dirHandle;
  OMMItemIntSpec ommItemIntSpec;
  // To request a specific service directory, set the serviceName on the request as follows:
  // attribInfo.setServiceName( RFA_String( "XYZ_SERVICE", 0, false) );
  // Otherwise, the request by default will be for all available services.
  reqMsg.setMsgModelType(MMT_DIRECTORY);
  reqMsg.setInteractionType(ReqMsg::InitialImageFlag | ReqMsg::InterestAfterRefreshFlag);
  attribInfo.setServiceName(_cfgVars.serviceName);//Optional: Set the service name in request//
  attribInfo.setDataMask(rfa::rdm::SERVICE_INFO_FILTER | rfa::rdm::SERVICE_STATE_FILTER);
  reqMsg.setAttribInfo(attribInfo);
  ommItemIntSpec.setMsg(&reqMsg);

  AppUtil::log(__LINE__, AppUtil::TRACE, "Create Directory Request %s", _cfgVars.serviceName.c_str());
  dirHandle = _pOMMConsumer->registerClient(_pEventQueue, &ommItemIntSpec, *this, NULL);
  return dirHandle;
}


Step 2: Add the Directory response process, at this step we will send Item Request after we have received the Directory response.

void StarterConsumer::processRespMsg(const rfa::sessionLayer::OMMItemEvent& event, const RespMsg& respMsg)
{
  switch(respMsg.getMsgModelType())
  {
    case MMT_LOGIN:
      processLoginResponse(event, respMsg);
      break;
    case MMT_MARKET_PRICE:
      processMarketPriceResponse(event, respMsg);
      break;
    case MMT_DIRECTORY:
      processDirectoryResponse(event, respMsg);//Add the Directory Response handle
      break;
    default:
      AppUtil::log(__LINE__, AppUtil::WARN, "<- Received unhandled OMMItemEvent msgModelType: %u", (UInt32)respMsg.getMsgModelType());
      break;
  }
}

void StarterConsumer::processDirectoryResponse(const rfa::sessionLayer::OMMItemEvent& event, const RespMsg& respMsg)
{
  RespStatus respStatus = respMsg.getRespStatus();
  // Check if we have refresh complete
  if (respMsg.getIndicationMask() & RespMsg::RefreshCompleteFlag)
  {
    // Check if the stream is open
    if (respMsg.getHintMask() & RespMsg::RespStatusFlag &&
    respStatus.getStreamState() == RespStatus::OpenEnum)
    {
      // Check if we have a usable payload
      if ((respMsg.getHintMask() & RespMsg::PayloadFlag) && !respMsg.getPayload().isBlank())
      {
        AppUtil::log(__LINE__, AppUtil::TRACE, "Received Directory Response");
  
        _pDecoder->decodeData(respMsg.getPayload());// TO-DO: Client can process the service status here//
        sendItemRequest(_cfgVars.itemName, _cfgVars.serviceName);
      }
    }
  }
}

This should have resolve the "Source unavailable" in case of service state on server side is actually up!


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.

For more information about this please refer to

RFA C++ Tutorial 9 (Directory message) and RFA C++ Tutorial 10 (Steps to request item after received Directory and Dictionary)

Upvotes

But for the completion, we can go further by checking that Service Status is actually up and ready for you to request items


Step 3: Decode Directory Response and check the Service State before sending Item Request, (Optional, but actually is the right thing to do), we will replace the TO-DO code in the Step 2)

//_pDecoder->decodeData(respMsg.getPayload());// TO-DO: Client can process the service status here//
//sendItemRequest(_cfgVars.itemName, _cfgVars.serviceName);

RFA_String testService = _cfgVars.serviceName;
UInt serviceState = 0;
UInt acceptingRequest = 0;
RespStatus stateStatus;
UInt stateStatusFlag = 0;
bool result = false;
stateStatus.clear();

result = getDirectoryServiceState(respMsg.getPayload(), testService, &serviceState, &acceptingRequest, &stateStatus, &stateStatusFlag);
if (result == true)
{
  AppUtil::log(__LINE__, AppUtil::TRACE, "Service: %s, ServiceState: %d, AcceptingRequest: %d, stateStatus: %s, stateStatusFlag", testService.c_str(), serviceState, acceptingRequest, stateStatus.getStatusText().c_str(), stateStatusFlag);
  
  if(serviceState == 1 && acceptingRequest == 1)
  {
    sendItemRequest(_cfgVars.itemName, _cfgVars.serviceName);// Send item request//
    AppUtil::log(__LINE__, AppUtil::TRACE, "Send item request");
  }
}
else
{
  AppUtil::log(__LINE__, AppUtil::TRACE, "Service: %s not found", testService.c_str());
}


This function is an example of how to decode and get the Service State and Accepting Request of the specified Service Name from Directory Response.

Note that our code is just an example serves as a guideline, the errors are omitted.

bool getDirectoryServiceState(const Data& inputData, const RFA_String service_name, UInt* _serviceState, UInt* _acceptingRequests, RespStatus* _stateStatus, UInt* _stateStatusFlag)
{
  const Map& input = static_cast <const Map&>(inputData);
  int outputchecker = 0;
  bool result = false;
  MapReadIterator itMap;
  itMap.start(input);
  // decode entries
  while (!itMap.off())
  {
    const MapEntry& mapEntry = static_cast <const MapEntry&>(itMap.value());
    RFA_String _serviceName = static_cast<const DataBuffer&> (mapEntry.getKeyData()).getAsString();
  
    if (_serviceName == service_name)// found service name
    {
      if (mapEntry.getData().getDataType() != FilterListEnum)
      {
      //ERROR Expected data datatype of FilterList
      return result;
      }
      const FilterList& filterList = static_cast<const FilterList&>(mapEntry.getData());
      FilterListReadIterator flRI;
      flRI.start(filterList);
      while (!flRI.off())
      {
        const FilterEntry& filterEntry = flRI.value();
        if (filterEntry.getFilterID() == SERVICE_STATE_ID)
        {
          if (filterEntry.getData().getDataType() != ElementListEnum)
          {
            //ERROR Expected data datatype of ElementList
            return result;
          }
          const ElementList& elementList = static_cast<const ElementList&>(filterEntry.getData());
          ElementListReadIterator elReadIter;
          elReadIter.start(elementList);
          while (!elReadIter.off())
          {
            const ElementEntry& element = elReadIter.value();
            const RFA_String& elementName = element.getName();
            
            // get ServiceState - UInt
            if (elementName == ENAME_SVC_STATE)
            {
              *_serviceState = (static_cast<const DataBuffer&> (element.getData())).getUInt();
              outputchecker |= 1;
            }
            // get AcceptingRequests - UInt
            else if (elementName == ENAME_ACCEPTING_REQS)
            {
              *_acceptingRequests = (static_cast<const DataBuffer&> (element.getData())).getUInt();
              outputchecker |= 2;
            }
            // get AcceptingRequests - RespStatus
            else if (elementName == ENAME_STATUS)
            {
              *_stateStatus = (static_cast<const DataBuffer&> (element.getData())).getRespStatus();
              *_stateStatusFlag = true;
              outputchecker |= 4;
            }
  
            if (outputchecker == (1 | 2 | 4))
            {
              return true;
            }
            elReadIter.forth();
          }
        }
        flRI.forth();
      }
    }
    itMap.forth();
  }
}


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.