From 95db83106231804f567011e89ab74f4950694f3a Mon Sep 17 00:00:00 2001
From: Michele Rastelli <michele@arangodb.com>
Date: Thu, 21 Mar 2024 20:17:45 +0100
Subject: [PATCH 1/3] set default connection ttl to 30s

---
 core/src/main/java/com/arangodb/ArangoDB.java                | 5 +++--
 core/src/main/java/com/arangodb/internal/ArangoDefaults.java | 1 +
 .../main/java/com/arangodb/internal/config/ArangoConfig.java | 3 +--
 .../main/java/com/arangodb/vst/internal/VstConnection.java   | 2 +-
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/com/arangodb/ArangoDB.java b/core/src/main/java/com/arangodb/ArangoDB.java
index 48ee8b287..62391eb10 100644
--- a/core/src/main/java/com/arangodb/ArangoDB.java
+++ b/core/src/main/java/com/arangodb/ArangoDB.java
@@ -513,9 +513,10 @@ public Builder maxConnections(final Integer maxConnections) {
         }
 
         /**
-         * Set the maximum time to life of a connection. After this time the connection will be closed automatically.
+         * Set the time to live of an inactive connection. After this time of inactivity the connection will be
+         * closed automatically.
          *
-         * @param connectionTtl the maximum time to life of a connection in milliseconds
+         * @param connectionTtl the time to live of a connection in milliseconds
          * @return {@link ArangoDB.Builder}
          */
         public Builder connectionTtl(final Long connectionTtl) {
diff --git a/core/src/main/java/com/arangodb/internal/ArangoDefaults.java b/core/src/main/java/com/arangodb/internal/ArangoDefaults.java
index aab635dd3..196eccdf3 100644
--- a/core/src/main/java/com/arangodb/internal/ArangoDefaults.java
+++ b/core/src/main/java/com/arangodb/internal/ArangoDefaults.java
@@ -45,6 +45,7 @@ public final class ArangoDefaults {
     public static final Protocol DEFAULT_PROTOCOL = Protocol.HTTP2_JSON;
     public static final String DEFAULT_USER = "root";
     public static final Integer DEFAULT_TIMEOUT = 0;
+    public static final Long DEFAULT_CONNECTION_TTL = 30_000L;
     public static final Boolean DEFAULT_USE_SSL = false;
     public static final Boolean DEFAULT_VERIFY_HOST = true;
     public static final Integer DEFAULT_CHUNK_SIZE = 30_000;
diff --git a/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java b/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
index 0aa67812f..d8e0bac1a 100644
--- a/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
+++ b/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
@@ -97,8 +97,7 @@ public void loadProperties(final ArangoConfigProperties properties) {
         chunkSize = properties.getChunkSize().orElse(ArangoDefaults.DEFAULT_CHUNK_SIZE);
         // FIXME: make maxConnections field Optional
         maxConnections = properties.getMaxConnections().orElse(null);
-        // FIXME: make connectionTtl field Optional
-        connectionTtl = properties.getConnectionTtl().orElse(null);
+        connectionTtl = properties.getConnectionTtl().orElse(ArangoDefaults.DEFAULT_CONNECTION_TTL);
         // FIXME: make keepAliveInterval field Optional
         keepAliveInterval = properties.getKeepAliveInterval().orElse(null);
         acquireHostList = properties.getAcquireHostList().orElse(ArangoDefaults.DEFAULT_ACQUIRE_HOST_LIST);
diff --git a/vst/src/main/java/com/arangodb/vst/internal/VstConnection.java b/vst/src/main/java/com/arangodb/vst/internal/VstConnection.java
index 8d9339463..ddd886d10 100644
--- a/vst/src/main/java/com/arangodb/vst/internal/VstConnection.java
+++ b/vst/src/main/java/com/arangodb/vst/internal/VstConnection.java
@@ -183,7 +183,7 @@ public synchronized void open() throws IOException {
             LOGGER.debug("[" + connectionName + "]: Start Callable");
 
             final long openTime = new Date().getTime();
-            final Long ttlTime = ttl != null ? openTime + ttl : null;
+            final Long ttlTime = ttl != null && ttl > 0 ? openTime + ttl : null;
             final ChunkStore chunkStore = new ChunkStore(messageStore);
             while (true) {
                 if (ttlTime != null && new Date().getTime() > ttlTime && messageStore.isEmpty()) {

From 5a202e9d76dc71713ea50217e1294a010363a99a Mon Sep 17 00:00:00 2001
From: Michele Rastelli <michele@arangodb.com>
Date: Thu, 21 Mar 2024 20:21:15 +0100
Subject: [PATCH 2/3] ttl resilience tests

---
 .../src/test/java/resilience/ClusterTest.java |  1 +
 .../java/resilience/SingleServerTest.java     |  1 +
 .../src/test/java/resilience/ttl/TtlTest.java | 68 +++++++++++++++++++
 3 files changed, 70 insertions(+)
 create mode 100644 resilience-tests/src/test/java/resilience/ttl/TtlTest.java

diff --git a/resilience-tests/src/test/java/resilience/ClusterTest.java b/resilience-tests/src/test/java/resilience/ClusterTest.java
index d16f4cbfa..7068927e1 100644
--- a/resilience-tests/src/test/java/resilience/ClusterTest.java
+++ b/resilience-tests/src/test/java/resilience/ClusterTest.java
@@ -52,6 +52,7 @@ static void afterAll() throws IOException {
     @BeforeEach
     void beforeEach() {
         enableAllEndpoints();
+        logs.reset();
     }
 
     protected static List<Endpoint> getEndpoints() {
diff --git a/resilience-tests/src/test/java/resilience/SingleServerTest.java b/resilience-tests/src/test/java/resilience/SingleServerTest.java
index 3aa587d93..89d028469 100644
--- a/resilience-tests/src/test/java/resilience/SingleServerTest.java
+++ b/resilience-tests/src/test/java/resilience/SingleServerTest.java
@@ -37,6 +37,7 @@ static void afterAll() throws IOException {
     @BeforeEach
     void beforeEach() {
         getEndpoint().enable();
+        logs.reset();
     }
 
     protected static Endpoint getEndpoint() {
diff --git a/resilience-tests/src/test/java/resilience/ttl/TtlTest.java b/resilience-tests/src/test/java/resilience/ttl/TtlTest.java
new file mode 100644
index 000000000..66aa37033
--- /dev/null
+++ b/resilience-tests/src/test/java/resilience/ttl/TtlTest.java
@@ -0,0 +1,68 @@
+package resilience.ttl;
+
+import com.arangodb.ArangoDB;
+import com.arangodb.ArangoDBAsync;
+import com.arangodb.Protocol;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import resilience.SingleServerTest;
+
+import java.time.Duration;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Stream;
+
+import static org.awaitility.Awaitility.await;
+
+/**
+ * @author Michele Rastelli
+ */
+class TtlTest extends SingleServerTest {
+
+    static Stream<Arguments> args() {
+        return Stream.of(
+                Arguments.of(Protocol.HTTP_JSON, "UNREGISTERED"),
+                Arguments.of(Protocol.HTTP2_JSON, "OUTBOUND GO_AWAY")
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("args")
+    void connectionTtl(Protocol p, String expectedLog) {
+        ArangoDB arangoDB = dbBuilder()
+                .connectionTtl(1_000L)
+                .maxConnections(1)
+                .protocol(p)
+                .build();
+
+        arangoDB.getVersion();
+
+        await()
+                .timeout(Duration.ofSeconds(3))
+                .until(() -> logs.getLogs().anyMatch(it -> it.getFormattedMessage().contains(expectedLog)));
+
+        arangoDB.getVersion();
+        arangoDB.shutdown();
+    }
+
+    @ParameterizedTest
+    @MethodSource("args")
+    void connectionTtlAsync(Protocol p, String expectedLog) throws ExecutionException, InterruptedException {
+        ArangoDBAsync arangoDB = dbBuilder()
+                .connectionTtl(1_000L)
+                .maxConnections(1)
+                .protocol(p)
+                .build()
+                .async();
+
+        arangoDB.getVersion().get();
+
+        await()
+                .timeout(Duration.ofSeconds(3))
+                .until(() -> logs.getLogs().anyMatch(it -> it.getFormattedMessage().contains(expectedLog)));
+
+        arangoDB.getVersion().get();
+        arangoDB.shutdown();
+    }
+
+}

From e727b41a472bf5e1e2de58a407831b4e10bbee62 Mon Sep 17 00:00:00 2001
From: Michele Rastelli <michele@arangodb.com>
Date: Thu, 21 Mar 2024 20:44:20 +0100
Subject: [PATCH 3/3] keep default ttl for VST unchanged

---
 .../src/main/java/com/arangodb/internal/ArangoDefaults.java | 2 +-
 .../java/com/arangodb/internal/config/ArangoConfig.java     | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/com/arangodb/internal/ArangoDefaults.java b/core/src/main/java/com/arangodb/internal/ArangoDefaults.java
index 196eccdf3..4e182970d 100644
--- a/core/src/main/java/com/arangodb/internal/ArangoDefaults.java
+++ b/core/src/main/java/com/arangodb/internal/ArangoDefaults.java
@@ -45,7 +45,7 @@ public final class ArangoDefaults {
     public static final Protocol DEFAULT_PROTOCOL = Protocol.HTTP2_JSON;
     public static final String DEFAULT_USER = "root";
     public static final Integer DEFAULT_TIMEOUT = 0;
-    public static final Long DEFAULT_CONNECTION_TTL = 30_000L;
+    public static final Long DEFAULT_CONNECTION_TTL_HTTP = 30_000L;
     public static final Boolean DEFAULT_USE_SSL = false;
     public static final Boolean DEFAULT_VERIFY_HOST = true;
     public static final Integer DEFAULT_CHUNK_SIZE = 30_000;
diff --git a/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java b/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
index d8e0bac1a..e01a40c9a 100644
--- a/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
+++ b/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
@@ -97,7 +97,8 @@ public void loadProperties(final ArangoConfigProperties properties) {
         chunkSize = properties.getChunkSize().orElse(ArangoDefaults.DEFAULT_CHUNK_SIZE);
         // FIXME: make maxConnections field Optional
         maxConnections = properties.getMaxConnections().orElse(null);
-        connectionTtl = properties.getConnectionTtl().orElse(ArangoDefaults.DEFAULT_CONNECTION_TTL);
+        // FIXME: make connectionTtl field Optional
+        connectionTtl = properties.getConnectionTtl().orElse(null);
         // FIXME: make keepAliveInterval field Optional
         keepAliveInterval = properties.getKeepAliveInterval().orElse(null);
         acquireHostList = properties.getAcquireHostList().orElse(ArangoDefaults.DEFAULT_ACQUIRE_HOST_LIST);
@@ -218,6 +219,9 @@ public void setMaxConnections(Integer maxConnections) {
     }
 
     public Long getConnectionTtl() {
+        if (connectionTtl == null && getProtocol() != Protocol.VST) {
+            connectionTtl = ArangoDefaults.DEFAULT_CONNECTION_TTL_HTTP;
+        }
         return connectionTtl;
     }