Skip to content

Commit 53bcf3b

Browse files
committed
Add read timeout support to BoltConnection
1 parent aa30d32 commit 53bcf3b

File tree

4 files changed

+53
-5
lines changed

4 files changed

+53
-5
lines changed

bolt-api-netty/src/main/java/org/neo4j/driver/internal/bolt/basicimpl/impl/BoltConnectionImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,11 @@ public CompletionStage<Void> close() {
487487
return close.exceptionally(ignored -> null);
488488
}
489489

490+
@Override
491+
public CompletionStage<Void> setReadTimeout(Duration duration) {
492+
return executeInEventLoop(() -> connection.setReadTimeout(duration));
493+
}
494+
490495
@Override
491496
public BoltConnectionState state() {
492497
var state = stateRef.get();
@@ -528,6 +533,11 @@ public boolean serverSideRoutingEnabled() {
528533
return serverSideRouting;
529534
}
530535

536+
@Override
537+
public Optional<Duration> defaultReadTimeout() {
538+
return connection.defaultReadTimeoutMillis();
539+
}
540+
531541
private CompletionStage<Void> executeInEventLoop(Runnable runnable) {
532542
var executeFuture = new CompletableFuture<Void>();
533543
Runnable stageCompletingRunnable = () -> {

bolt-api-netty/src/main/java/org/neo4j/driver/internal/bolt/basicimpl/impl/async/NetworkConnection.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import io.netty.channel.ChannelFutureListener;
2424
import io.netty.channel.ChannelHandler;
2525
import io.netty.channel.EventLoop;
26+
import java.time.Duration;
2627
import java.util.Collections;
28+
import java.util.Optional;
2729
import java.util.concurrent.CompletableFuture;
2830
import java.util.concurrent.CompletionStage;
2931
import java.util.concurrent.TimeUnit;
@@ -56,7 +58,8 @@ public class NetworkConnection implements Connection {
5658
private final boolean ssrEnabled;
5759
private final BoltProtocol protocol;
5860

59-
private final Long connectionReadTimeout;
61+
private final Duration defaultReadTimeout;
62+
private Duration readTimeout;
6063

6164
private ChannelHandler connectionReadTimeoutHandler;
6265

@@ -70,8 +73,10 @@ public NetworkConnection(Channel channel, LoggingProvider logging) {
7073
this.telemetryEnabled = ChannelAttributes.telemetryEnabled(channel);
7174
this.ssrEnabled = ChannelAttributes.ssrEnabled(channel);
7275
this.protocol = BoltProtocol.forChannel(channel);
73-
this.connectionReadTimeout =
74-
ChannelAttributes.connectionReadTimeout(channel).orElse(null);
76+
this.defaultReadTimeout = ChannelAttributes.connectionReadTimeout(channel)
77+
.map(Duration::ofSeconds)
78+
.orElse(null);
79+
this.readTimeout = defaultReadTimeout;
7580
}
7681

7782
@Override
@@ -179,6 +184,25 @@ public EventLoop eventLoop() {
179184
return channel.eventLoop();
180185
}
181186

187+
@Override
188+
public Optional<Duration> defaultReadTimeoutMillis() {
189+
return Optional.ofNullable(defaultReadTimeout);
190+
}
191+
192+
@Override
193+
public void setReadTimeout(Duration duration) {
194+
if (!channel.eventLoop().inEventLoop()) {
195+
throw new IllegalStateException("This method may only be called in the EventLoop");
196+
}
197+
198+
if (duration != null && duration.toMillis() > 0) {
199+
// only values greater than zero milliseconds are supported
200+
this.readTimeout = duration;
201+
} else {
202+
this.readTimeout = this.defaultReadTimeout;
203+
}
204+
}
205+
182206
private CompletionStage<Void> writeMessageInEventLoop(Message message, ResponseHandler handler) {
183207
var future = new CompletableFuture<Void>();
184208
Runnable runnable = () -> {
@@ -215,8 +239,9 @@ private void registerConnectionReadTimeout(Channel channel) {
215239
throw new IllegalStateException("This method may only be called in the EventLoop");
216240
}
217241

218-
if (connectionReadTimeout != null && connectionReadTimeoutHandler == null) {
219-
connectionReadTimeoutHandler = new ConnectionReadTimeoutHandler(connectionReadTimeout, TimeUnit.SECONDS);
242+
if (this.readTimeout != null && connectionReadTimeoutHandler == null) {
243+
connectionReadTimeoutHandler =
244+
new ConnectionReadTimeoutHandler(readTimeout.toMillis(), TimeUnit.MILLISECONDS);
220245
channel.pipeline().addFirst(connectionReadTimeoutHandler);
221246
log.log(System.Logger.Level.DEBUG, "Added ConnectionReadTimeoutHandler");
222247
messageDispatcher.setBeforeLastHandlerHook(() -> {

bolt-api-netty/src/main/java/org/neo4j/driver/internal/bolt/basicimpl/impl/spi/Connection.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.neo4j.driver.internal.bolt.basicimpl.impl.spi;
1818

1919
import io.netty.channel.EventLoop;
20+
import java.time.Duration;
21+
import java.util.Optional;
2022
import java.util.concurrent.CompletionStage;
2123
import org.neo4j.driver.internal.bolt.api.BoltServerAddress;
2224
import org.neo4j.driver.internal.bolt.basicimpl.impl.messaging.BoltProtocol;
@@ -48,4 +50,8 @@ public interface Connection {
4850
CompletionStage<Void> close();
4951

5052
EventLoop eventLoop();
53+
54+
Optional<Duration> defaultReadTimeoutMillis();
55+
56+
void setReadTimeout(Duration duration);
5157
}

bolt-api/src/main/java/org/neo4j/driver/internal/bolt/api/BoltConnection.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.time.Duration;
2020
import java.util.Map;
21+
import java.util.Optional;
2122
import java.util.Set;
2223
import java.util.concurrent.CompletionStage;
2324
import org.neo4j.driver.internal.bolt.api.values.Value;
@@ -75,6 +76,10 @@ CompletionStage<BoltConnection> runInAutoCommitTransaction(
7576

7677
CompletionStage<Void> close();
7778

79+
// ----- STATE UPDATES -----
80+
81+
CompletionStage<Void> setReadTimeout(Duration duration);
82+
7883
// ----- MUTABLE DATA -----
7984

8085
BoltConnectionState state();
@@ -92,4 +97,6 @@ CompletionStage<BoltConnection> runInAutoCommitTransaction(
9297
boolean telemetrySupported();
9398

9499
boolean serverSideRoutingEnabled();
100+
101+
Optional<Duration> defaultReadTimeout();
95102
}

0 commit comments

Comments
 (0)