You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two pre-existing problems surfaced during the review of #110 (neither introduced there).
1. CancelOpRequest can arrive before the operation registers itself
OperationRequest execution is submitted to the shared pool, and the LocalRequest registers itself in its constructor on that pool thread. A CancelOpRequest for the same message id dispatched right behind the OperationRequest (the serial queue keeps cancels timely by design) can therefore be processed before the registration exists and cancels nothing. The race predates #110 — with the old unordered pool the cancel could even be processed first.
Possible direction: register the request id synchronously during ordered classification (inside the serial dispatch task) before re-submitting the execution to the pool, or park unmatched cancels for a short grace period.
2. Jetty server never ends the lifecycle of cached principals
OpenICFWebSocketCreator.principalCache caches one SinglePrincipal per principal name and never evicts:
ConnectionPrincipal.close()/doClose() is never called for cached principals — OpenICFWebSocketServletBase.destroy() shuts down the scheduler and releases the framework but does not touch the cache. After [#109] Serialize WebSocket message dispatch per socket to prevent out-of-order processing #110 the per-principal send executor is shut down in doClose(), so today it is only reclaimed because its thread is a daemon.
SinglePrincipal.hasCloseBeenCalled is set on the first onWebSocketClose and never reset, so for every later connection served by the same cached principal the close event is silently swallowed — OperationMessageListener.onClose is not invoked and the connection group is not told the holder went away.
Closing cached principals from destroy() and making the close guard per-connection would fix both.
Two pre-existing problems surfaced during the review of #110 (neither introduced there).
1.
CancelOpRequestcan arrive before the operation registers itselfOperationRequestexecution is submitted to the shared pool, and theLocalRequestregisters itself in its constructor on that pool thread. ACancelOpRequestfor the same message id dispatched right behind theOperationRequest(the serial queue keeps cancels timely by design) can therefore be processed before the registration exists and cancels nothing. The race predates #110 — with the old unordered pool the cancel could even be processed first.Possible direction: register the request id synchronously during ordered classification (inside the serial dispatch task) before re-submitting the execution to the pool, or park unmatched cancels for a short grace period.
2. Jetty server never ends the lifecycle of cached principals
OpenICFWebSocketCreator.principalCachecaches oneSinglePrincipalper principal name and never evicts:ConnectionPrincipal.close()/doClose()is never called for cached principals —OpenICFWebSocketServletBase.destroy()shuts down the scheduler and releases the framework but does not touch the cache. After [#109] Serialize WebSocket message dispatch per socket to prevent out-of-order processing #110 the per-principal send executor is shut down indoClose(), so today it is only reclaimed because its thread is a daemon.SinglePrincipal.hasCloseBeenCalledis set on the firstonWebSocketCloseand never reset, so for every later connection served by the same cached principal the close event is silently swallowed —OperationMessageListener.onCloseis not invoked and the connection group is not told the holder went away.Closing cached principals from
destroy()and making the close guard per-connection would fix both.