How to put a timeout on receiving messages in asynchronous mode in C Solace API?

Can anyone please share any idea.
I want to pass a timeout value within which the message must be received in C Solace Api.
receive(timeout) is there for Java Api. Is there anything similar in Solace C api.

Best Answers

  • TomF
    TomF Member, Employee Posts: 406 Solace Employee
    #2 Answer ✓

    Hi @TestSolace, could you describe what you'd like to do in more detail? It sounds like a message time to live (TTL) could be what you're after. This will hold a message on a queue for the TTL, and after that expires the message is optionally moved to a dead message queue or dropped. You can set the TTL on the message and/or the queue itself. See TTL docs.

  • TomF
    TomF Member, Employee Posts: 406 Solace Employee
    #3 Answer ✓

    Hi @TestSolace - ah-ha! You definitely want Request/Reply messaging in that case. Have a look at the documentation link. You then simply set the response timeout to the value you need and if the consumer doesn't reply within that timeout, the function returns a status code.

    Use:
    solClient_session_sendRequest()

    To send your message. In your receiver, once you've got the incoming request, processed it, and you're ready to send a response, use:

    solClient_session_sendReply()

    Remember that you should not call and sends from within the message receive callback - it should be called from the application thread.

    solClient_rxMsgCallback_returnCode_t className::sessionMessageReceiveCallback(...) {
      processMsg();
      solClient_session_sendReply();   // DON'T DO THIS!
    }
    

    Do something like:

    solClient_rxMsgCallback_returnCode_t className::sessionMessageReceiveCallback(...) {
      processMsg();
      appendMsgOnStructure();
    }
    
    // in application thread
    while( getMsgInStructure() ) {
      solClient_session_sendReply();
    }
    
  • Ragnar
    Ragnar Member, Employee Posts: 64 Solace Employee
    #4 Answer ✓

    The fundamental purpose of messaging platforms is for asynchronous communication. The power is in providing a framework in which data can be published/consumed without end-to-end synchronization or connections. This lends itself well to things like sensor data, published into the broker, where the publisher doesn't care if none, one, or multiple consumers process the information. This is the core of a publisher/subscriber model, some application publishes, other applications consume. The applications are unaware of each other.
    That said, there is still occasionally a need for end-to-end communication and for that the request-reply model exists. It is expected this would be the exception rather than the norm. If you are developing a solution where synchronized communication is required end to end you might be better off looking at some other archiecture such as server/client with raw sockets.
    Time-to-live, when set on a published message, allows the Solace broker to 'expire' and remove persistent messages that are not consumed. This is an house cleaning operation and affects persistent messages but it is not signaled back to the publisher, so won't help your use case.
    Request-reply: allows the publisher to block and wait for a reply. But your consuming application has to be written to send te reply when it is done. As has been said, this exists to solve end-to-end synchronization in a messaging system and may be suitable for you here.
    Condition variables are an advanced synchronization mechanism in many operating systems. They are not a part of messaging and the sample code in OS.h and OS.c merely shows one way you can define a common C interface to condition variables in a portable way so the code that uses them doesn't have to be rewritten for every target platform. These are not part of the Solace API, they are simply abstractions for a tool that might be used by advanced developers. As none of the Solace examples use this code, it will probably be removed from the samples in a future release.
    As the Solace request-reply interface is synchronous and blocking, there is no need for your application to use a condition variable at all.

Answers

  • Ragnar
    Ragnar Member, Employee Posts: 64 Solace Employee

    receive(timeout) is a synchronous interface. The C API does not offer a synchronous interface. It would be highly unusual to configure a timeout on an asynchronous callback interface. It would be common for in a send-for-reply paradigm, such as subscription/subscription confirm, or connect/connect-confirm. or request-reply, and asynchronous timeout events are available in the C API for the first two. However there is no concept of an asynchronous timeout for simply receiving messages.
    Ragnar

  • TomF
    TomF Member, Employee Posts: 406 Solace Employee
    #6 Answer ✓

    Hi @TestSolace, could you describe what you'd like to do in more detail? It sounds like a message time to live (TTL) could be what you're after. This will hold a message on a queue for the TTL, and after that expires the message is optionally moved to a dead message queue or dropped. You can set the TTL on the message and/or the queue itself. See TTL docs.

  • TestSolace
    TestSolace Member Posts: 16

    Hi @TomF ,
    Thank you for the Answer.
    I am trying to send a message and it should be received within the given timeout.
    For ex: If i pass 10 sec as time out value,- within 10 second if the receiving window doesn't receive the message, then it should throw an error message.
    I did try with Time To live property but i am unable to achieve it. Can you please give any example on how to make it to work.
    The way I am doing is:

    Step 1-

    I am creating and connecting to Solace session.
    In the session i am enabling the "Respect message TTL property" in my session.
    Props[propIndex++] = SOLCLIENT_ENDPOINT_PROP_RESPECTS_MSG_TTL;
    Props[propIndex++] = SOLCLIENT_PROP_ENABLE_VAL;
    Step 2:

    I am setting the TTL value and trying to produce the Timeout.

    solClient_int64_t ttl = 1;
    solClient_bool_t dmqe = FALSE;
    const char *text_p = "Hello World!";
    if ( SOLCLIENT_OK != solClient_msg_alloc ( &msg_p ) )
    { std::cout << "Failed to Allocate memory \n"; }
    if ( SOLCLIENT_OK != solClient_msg_setDeliveryMode ( msg_p, SOLCLIENT_DELIVERY_MODE_DIRECT ) )
    { std::cout << "Failed to set message delivery mode"; }
    if ( (solClient_msg_setTimeToLive ( msg_p, ttl ) ) != SOLCLIENT_OK ) { Do Something }
    if ( ( solClient_msg_setDMQEligible ( msg_p, dmqe ) ) != SOLCLIENT_OK ) { Do something }
    destination.destType = SOLCLIENT_TOPIC_DESTINATION;
    destination.dest = TopicName.c_str() ;
    if ( SOLCLIENT_OK != solClient_msg_setDestination ( msg_p, &destination, sizeof ( destination ) ) )
    { std::cout << "Failed to set destination \n";}
    if(SOLCLIENT_OK != solClient_msg_setBinaryAttachment ( msg_p, text_p, ( solClient_uint32_t ) strlen ( (char *)text_p ) ))
    { std::cout << "Failed to Add content to message \n"; }
    if ( SOLCLIENT_OK != solClient_session_sendMsg ( session_p, msg_p ) )
    { std::cout << "Failed to Send message \n"; }
    freeMessage:
    if ( SOLCLIENT_OK != solClient_msg_free ( &msg_p ) )

    {std::cout << "Failed to free message \n";}

    I don't see the message expiring although i have given 1 second.

    It is still received by the receiving function.

    solClient_rxMsgCallback_returnCode_t
    className::sessionMessageReceiveCallback(solClient_opaqueSession_pt opaqueSession_p, solClient_opaqueMsg_pt msg_p, void *user_p)
    {
    printf ( "Received message:\n" );
    solClient_msg_dump ( msg_p, NULL, 0 );
    printf ( "\n" );
    return SOLCLIENT_CALLBACK_OK;

    }

    Is my proccess wrong? I have set the message mode to DIRECT.
    Do i need to add any other session property to it.

  • TomF
    TomF Member, Employee Posts: 406 Solace Employee

    Hi @TestSolace, we're getting in to some fundamentals of messaging here, so excuse me but I need to understand more about what you're trying to do.

    I am trying to send a message and it should be received within the given timeout.

    When you say "received" - received by whom? Do you mean you want to know the broker has successfully got the message? Or that the end consumer got it within that time? Who do you want to notify? The original publisher?

    If you want the original publisher to get the exception that there's been no response, you should use the request/response messaging style.

  • TestSolace
    TestSolace Member Posts: 16

    Hi @TomF
    By sending the message, i want to ensure that the consumer has got the message within that time.
    Thanks.

  • TomF
    TomF Member, Employee Posts: 406 Solace Employee
    #10 Answer ✓

    Hi @TestSolace - ah-ha! You definitely want Request/Reply messaging in that case. Have a look at the documentation link. You then simply set the response timeout to the value you need and if the consumer doesn't reply within that timeout, the function returns a status code.

    Use:
    solClient_session_sendRequest()

    To send your message. In your receiver, once you've got the incoming request, processed it, and you're ready to send a response, use:

    solClient_session_sendReply()

    Remember that you should not call and sends from within the message receive callback - it should be called from the application thread.

    solClient_rxMsgCallback_returnCode_t className::sessionMessageReceiveCallback(...) {
      processMsg();
      solClient_session_sendReply();   // DON'T DO THIS!
    }
    

    Do something like:

    solClient_rxMsgCallback_returnCode_t className::sessionMessageReceiveCallback(...) {
      processMsg();
      appendMsgOnStructure();
    }
    
    // in application thread
    while( getMsgInStructure() ) {
      solClient_session_sendReply();
    }
    
  • TestSolace
    TestSolace Member Posts: 16
    edited January 2021 #11

    Hi @TomF,
    Thank you for the Answer. I am clear as to how to approach the issue i am facing.
    Apart from it, I want to understand the use of TTL.
    Is it wrong to use the way i have used it.
    When to use TTL.
    Can you please direct me to any document that explains on Different Load Balancing technique use by Solace.
    Thanks,
    Pooja.

  • TestSolace
    TestSolace Member Posts: 16
    edited January 2021 #12

    Hi @TomF / @Ragnar ,
    After some research, I got a method which is :
    "BOOL condTimedWait ( CONDITION_T * cond_p, MUTEX_T * mutex_p, int timeoutSec );"
    It is this above method which i want to use for timeout. The existing examples in solace document uses SleepInsec(1) from "os.h" file but i have to use condTimeWait.
    I got it from Os.h file.
    Thanks,

  • Ragnar
    Ragnar Member, Employee Posts: 64 Solace Employee
    #13 Answer ✓

    The fundamental purpose of messaging platforms is for asynchronous communication. The power is in providing a framework in which data can be published/consumed without end-to-end synchronization or connections. This lends itself well to things like sensor data, published into the broker, where the publisher doesn't care if none, one, or multiple consumers process the information. This is the core of a publisher/subscriber model, some application publishes, other applications consume. The applications are unaware of each other.
    That said, there is still occasionally a need for end-to-end communication and for that the request-reply model exists. It is expected this would be the exception rather than the norm. If you are developing a solution where synchronized communication is required end to end you might be better off looking at some other archiecture such as server/client with raw sockets.
    Time-to-live, when set on a published message, allows the Solace broker to 'expire' and remove persistent messages that are not consumed. This is an house cleaning operation and affects persistent messages but it is not signaled back to the publisher, so won't help your use case.
    Request-reply: allows the publisher to block and wait for a reply. But your consuming application has to be written to send te reply when it is done. As has been said, this exists to solve end-to-end synchronization in a messaging system and may be suitable for you here.
    Condition variables are an advanced synchronization mechanism in many operating systems. They are not a part of messaging and the sample code in OS.h and OS.c merely shows one way you can define a common C interface to condition variables in a portable way so the code that uses them doesn't have to be rewritten for every target platform. These are not part of the Solace API, they are simply abstractions for a tool that might be used by advanced developers. As none of the Solace examples use this code, it will probably be removed from the samples in a future release.
    As the Solace request-reply interface is synchronous and blocking, there is no need for your application to use a condition variable at all.