Andrea Cosentino created CAMEL-24788:
----------------------------------------

             Summary: camel-vertx-websocket: a shared websocket host is 
unregistered when the first of its consumers stops
                 Key: CAMEL-24788
                 URL: https://issues.apache.org/jira/browse/CAMEL-24788
             Project: Camel
          Issue Type: Bug
          Components: camel-vertx-websocket
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino


h3. Summary

All {{vertx-websocket}} consumers bound to the same host and port share one 
{{VertxWebsocketHost}}, but the host is dropped from the component registry as 
soon as the *first* of those consumers stops. Every consumer that stops 
afterwards is silently ignored, its Vert.x route is never removed, and the HTTP 
server it runs on is never stopped.

h3. Detail

{{VertxWebsocketHostKey}} is {{\{host, port\}}} only (lines 25-26), so 
{{connectConsumer}} shares a single host across every path on that port:

{code:java}
VertxWebsocketHost host = vertxHostRegistry.computeIfAbsent(hostKey, key -> { 
... });
host.connect(consumer);
{code}
({{VertxWebsocketComponent}} line 167)

but {{disconnectConsumer}} removes that shared host on the first stop:

{code:java}
VertxWebsocketHost vertxWebsocketHost = vertxHostRegistry.remove(hostKey);
if (vertxWebsocketHost != null) {
    vertxWebsocketHost.disconnect(configuration.getWebsocketURI().getPath());
}
{code}
({{VertxWebsocketComponent}} line 205)

With two consumers, {{/a}} and {{/b}}, on the same port:

* stopping the {{/a}} route removes the shared host from the registry, then 
{{disconnect("/a")}} removes only that route. {{VertxWebsocketHost.disconnect}} 
(line 166) stops the server only once its own {{routeRegistry}} is empty, and 
{{/b}} is still in it, so the server keeps running - correctly, at that point;
* stopping the {{/b}} route then finds *nothing* in the registry: {{remove}} 
returns null, the null guard skips, and route {{/b}} is never removed. **The 
server carries on listening after every Camel route is stopped.**
* starting a consumer on that host and port again builds a *second* 
{{VertxWebsocketHost}} with a new Router and calls {{start()}} on a port the 
first server still holds.

{{VertxWebsocketComponent.doStop}} (line 157) closes Vert.x only when Camel 
created it, so when the application supplies its own {{Vertx}} or {{Router}} - 
the usual arrangement under Spring Boot and Quarkus - nothing ever tears the 
server down.

h3. Two smaller problems in the same lifecycle

* {{VertxWebsocketHost}} line 54 keeps {{routeRegistry}} in a plain 
{{HashMap}}, mutated by {{connect}} and {{disconnect}}, i.e. on route start and 
stop. The field right below it is a {{CopyOnWriteArrayList}} carrying an 
explicit {{// thread-safe}} comment, so the difference looks accidental rather 
than considered. Route start/stop is concurrent under the supervising route 
controller.
* {{VertxWebsocketHost.disconnect}} lines 164-165 do 
{{routeRegistry.remove(path)}} and then {{route.remove()}} with no null check, 
so an unknown or repeated path throws a {{NullPointerException}}.

Found by a source audit of {{components/camel-vertx}} at be3dd651866f.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to