.NET best practices for lifetimes/instancing of context/session?

Kiwidude Member Posts: 7

We are looking to add Solace support for publishing/receiving from Solace Topics & Queues to our existing .NET C# codebase that already handles MSMQ and MQ. One thing that I have not come across in the documentation / examples is how we should be instancing the IContext and ISession - the code examples simply create one of every object to send/receive a single message and exit which isn't quite a "real world" example :).

For instance with MQ if we wanted to listen to four queues we create four threads each listening to their specific queue and processing their messages. If we were to apply this same pattern to Solace, the question becomes how we should be instancing/sharing across those threads. Should we have a single IContext for our executable process, shared by all listening and publishing threads? Then within that do we have a single ISession shared by all, or should each listening thread create it's own ISession? We also have other code doing publishing - should each thread publishing a message create an ISession/dispose after sending a message or share a single ISession with the listening threads...

Suggestions or pointing me to something I missed would be much appreciated!


Best Answers


  • Kiwidude
    Kiwidude Member Posts: 7

    Thanks so much for the quick reply - that sounds great. I did "suspect" that may be the answer but for sure wanted some confirmation from yourselves. We are definitely not going to be near high performance range in our usage. All the links are much appreciated too.

  • TomF
    TomF Member, Employee Posts: 406 Solace Employee

    Glad to help @Kiwidude - if you have a minute, could you mark the question as answered? It would help other users.

  • Kiwidude
    Kiwidude Member Posts: 7

    Sure - if you can tell me how? I'm looking at all the icons and not seeing anything that looks like it would mark that as an answer?
    Still working through those documentation links and thinking about our scenarios/existing code pattern that I am trying to align Solace with. With the current MQ based design we effectively have x threads doing a synchronous read of their specific transactional queues, and if an error occurs on that thread while processing that message the message is left on the queue. This offers protection for temporary network blips to the database during processing for instance.

    The Solace API seems a little "unexpected" from what I have seen so far in that it is the Session that is prescribing the event delegate for handing messages - the Topic or Queue subscribe methods would appear just to be filtering what messages that handler would receive. So having only one session but trying to listen to multiple queues asynchronously would appear to not fit very nicely with our existing application design. Which would then force us into a completely different design like you mention of structures for each broker queue and then threads reading from those - but that sort of design has it's own problems and complications, particularly that at first glance we lose the ability to be semi-transactional. What if our service is stopped with these messages sitting in the interim structures - they will be lost instead of just remaining on their queue etc. Likely I am perhaps missing something obvious...

  • hong
    hong Guest Posts: 480 ✭✭✭✭✭

    @Kiwidude You posted it as a discussion. That's why you can't accept the answer. Only when you post a Q&A can you accept an answer. I've changed it to Q&A and you can accept the answer now by clicking Yes in "Did this answer the question?".

  • allmhhuran
    allmhhuran Member Posts: 41 ✭✭✭
    edited August 2020 #10

    I have a followup to this question. As far as I understand...

    • flows are only available on the subscriber side, not the publisher side.
    • publishing guaranteed messages will result in a session level acknowledgement event
    • This event can be used by the client to know that the message has been received by the broker

    Suppose I am publishing guaranteed messages. As the publisher, I need to know which messages have been successfully received so I can update some kind of "high water mark" on my outgoing messages. I can evidently do this by processing the acknowledgement events. Now, it's not clear to me what that event quite means if using the Send(IMessage[]...) call, but I'll leave that to another question.

    On the subject of this question, however, this seems to imply that publishing guaranteed messages would require one session per publisher. Otherwise, how would I know how to route the acknowledgement event back to the "correct" publisher? But the apparent need for multiple sessions seems to conflict with the best practise advice, and the advice here, of typically using a single session except in unusual circumstances. I wouldn't call having multiple different publications particularly unusual, so the apparent need for multiple sessions for guaranteed messages confuses me. I feel like I must have missed something somewhere.

  • Kiwidude
    Kiwidude Member Posts: 7

    @allmhhuran - will be interesting to see the experts advice on this but this is what I did. My service class for the Solace context/session exposes an event for publishing classes to temporarily subscribe to when needed, and delegates to any of those when it gets a session event. Then in the publisher code I set the CorrelationKey property of the IMessage that you are publishing. When the session event fires on the service and passed through to my publisher event handler, the SessionEventArgs includes the same CorrelationKey property so you can check to see if is the droid you are looking for. Seems like it would do the job for our low volumes but yet to test it in anger :smile:

  • allmhhuran
    allmhhuran Member Posts: 41 ✭✭✭

    Ah yes, the CorrelationKey on the EventArgs was the bit I was missing. I have found that in one of the code samples now.
    It sounds like you've already finished your build, but for what it's worth, I am using System.Threading.Tasks.Dataflow for my pipelines under the covers. I will probably be asking a question soon enough on this forum as to whether the acknowledgements always come back in the same order the messages were sent. If so, the correlationKey could be used to map messages back to a subscriber pipeline, and then a dataflow JoinBlock could be used to very efficiently allocate each ack with it's original message, since Dataflow will also guarantee order. This eliminates the need for buffers and lookups when processing the acks.

    Having said that, I'm not sure what I would do with a RejectedMessageError response, given a requirement to keep messages in order. If 2 messages are sent, and then the first comes back as rejected, while the second comes back as accepted, I suppose all one can do is drop the message. Retransmitting at that point would break message ordering. Of course, this only applies if batch sending. If sending single messages you could always wait for the first ack before sending the second, and if the first is rejected, I suppose you just kill the pipelin eentirely and raise the fault back to the generating application.