davsclaus commented on code in PR #27858:
URL: https://github.com/apache/camel/pull/27858#discussion_r4279068174


##########
components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ZooKeeperProducer.java:
##########
@@ -66,9 +66,8 @@ public ZooKeeperProducer(ZooKeeperEndpoint endpoint) {
     @Override
     public void process(Exchange exchange) throws Exception {
 
-        if (connection == null) {
-            connection = this.zkm.getConnection();
-        }
+        // a new connection when the session of the previous one expired
+        connection = this.zkm.getConnection();

Review Comment:
   Nit (non-blocking): with concurrent senders the shared `connection` field is 
written by several threads. A local variable keeps each message on the handle 
it got here (the async branches further down read the field again):
   
   ```java
   ZooKeeper zk = this.zkm.getConnection();
   connection = zk;
   ProductionContext context = new ProductionContext(zk, exchange);
   ```
   
   The `asynchronously...(connection, context)` calls below could then also use 
`zk`.



##########
components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ConnectionHolder.java:
##########
@@ -33,43 +33,71 @@
 public class ConnectionHolder implements Watcher {
     private static final Logger LOG = 
LoggerFactory.getLogger(ConnectionHolder.class);
 
-    private CountDownLatch connectionLatch = new CountDownLatch(1);
+    private volatile CountDownLatch connectionLatch = new CountDownLatch(1);
 
     private ZooKeeperConfiguration configuration;
 
-    private ZooKeeper zookeeper;
+    private volatile ZooKeeper zookeeper;
 
     public ConnectionHolder(ZooKeeperConfiguration configuration) {
         this.configuration = configuration;
     }
 
+    /**
+     * Returns the ZooKeeper handle, and creates one when there is none or 
when the current one can no longer be used: a
+     * handle whose session expired (or that was closed) stays closed for 
good, so a new handle with a new session is
+     * needed. Waits until the new handle is connected.
+     */
     public ZooKeeper getZooKeeper() {
-        if (zookeeper != null) {
-            return zookeeper;
-        }
-        if (configuration.getConnectString() == null) {
-            throw new RuntimeCamelException(
-                    "Cannot create ZooKeeper connection as connection string 
is null. Have servers been configured?");
-        }
-        try {
-            zookeeper = new ZooKeeper(configuration.getConnectString(), 
configuration.getTimeout(), this);
-        } catch (Exception e) {
-            throw RuntimeCamelException.wrapRuntimeCamelException(e);
+        ZooKeeper created;
+        CountDownLatch latch;
+        synchronized (this) {

Review Comment:
   Nit (non-blocking): the producer now calls `getZooKeeper()` for every 
message, so each send takes this monitor. Since `zookeeper` is volatile, a fast 
path before the lock keeps the common case lock-free:
   
   ```java
   ZooKeeper current = zookeeper;
   if (current != null && current.getState().isAlive()) {
       return current;
   }
   synchronized (this) {
       current = zookeeper;
       ...
   ```



##########
components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ZooKeeperConsumer.java:
##########
@@ -199,11 +208,16 @@ private void backoffAndThenRestart() {
                             .build()
                             .run(getEndpoint().getCamelContext(), () -> true);
 
-                    initializeConsumer();
+                    if (isRunAllowed()) {
+                        connection = zkm.getConnection();
+                        initializeConsumer();

Review Comment:
   Suggestion (non-blocking): the PR description mentions that a stop between 
the `isRunAllowed()` check and `getConnection()` can create a handle after 
`doStop` closed the holder. That handle then keeps its session and its two 
client threads (SendThread/EventThread) alive after the route stopped. A 
re-check here would close it:
   
   ```suggestion
                           connection = zkm.getConnection();
                           if (!isRunAllowed()) {
                               zkm.shutdown();
                               return false;
                           }
                           initializeConsumer();
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to