I am building a “simple” monitor for our pubsub+ broker.
For this moinitor, in the case of some kind of connectivity issue, I would like to tear down and completely rebuild the solace connection from the SDK object level.
I explicitly do not want to use the built in retry functionality in the SDK, because
- If there was some kind of object initialization problem, the retry will retry with the same configuration. Since the monitor is explicitly for gathering telemetry and service health, it might want to try multiple configurations.
- I want to retry with exponential backoff and potentially jitter. I beleive the built-in retry does not have backoff (it might have jitter).
The only SDK object which I want to initialize for the lifetime of the monitor application is the ContextFactory itself - ie one call toContextFactory.Instance.Init()
So, the other objects I need to work with are:
IContext
ISession
IFlow
IQueue
ITopic
All of these are IDisposable, IFlow has Stop(), and ISession has Disconnect().
In the case of this monitor, the IQueue I am using is a temporary queue - ie, created via ISession.CreateTemporaryQueue(). I do not have a need for guaranteed delivery of messages to a monitor queue even when the monitor is not running so that it can get its messages when it reconnects. Loss of messages when the monitor is not running is fine.
If I wanted to tear down all of this cleanly, what is the correct order to do it in?
I currently have this method, which is the anti-method of another method called CreateSolaceObjects():
private void DisposeSolaceObjects()
{
try { _flow?.Stop(); } catch { }
try { _flow?.Dispose(); } catch { }
_flow = null;
try { _queue?.Dispose(); } catch { }
_queue = null;
try { _session?.Disconnect(); } catch { }
try { _session?.Dispose(); } catch { }
_session = null;
try { _topic?.Dispose(); } catch { }
_topic = null;
try { _context?.Dispose(); } catch { }
_context = null;
}
In my implementation DownError events are routed through a System.Threading.Channel to a signal handler background task, which calls this method/anti-method pair as needed.
But when trying to reconnect after a DownError (and after DisposeSolaceObjects has been called) I regularly get this error:
Operation Error: ReturnCode = SOLCLIENT_FAIL Error Info: (Subcode=MaxClientsForQueueReached, Error string=Max clients exceeded for queue, Response code= 503
How can I avoid this? I would have thought that if everything has been stopped/disconnected and disposed, then the client connection would be gone and the queue would no longer exist (and in the case of a temporary queue, it would be a new queue anyway), so I don’t understand how the “same” queue is still there, and the broker thinks some other client (session? flow?) is still connected to it.