Skip to content

Commit 5e57c9e

Browse files
committed
Allow tx timeout to be 0 or null.
Adjust TestKit back end to accept * `null` timeout: send `null` to server (or omit as it's the default) * and integer: configure as timeout in milliseconds * omitted timeout: don't explicitly configure the timeout (user driver default)
1 parent 6f28a02 commit 5e57c9e

File tree

5 files changed

+117
-24
lines changed

5 files changed

+117
-24
lines changed

driver/src/main/java/org/neo4j/driver/TransactionConfig.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,26 +183,33 @@ public static class Builder
183183
private Duration timeout;
184184
private Map<String,Object> metadata = emptyMap();
185185

186+
/**
187+
* Value used to signal {@link #withTimeout(Duration)} to use the server-side configured default timeout.
188+
*/
189+
public static final Duration SERVER_DEFAULT_TIMEOUT = null;
190+
186191
private Builder()
187192
{
188193
}
189194

190195
/**
191196
* Set the transaction timeout. Transactions that execute longer than the configured timeout will be terminated by the database.
197+
* Use {@link #SERVER_DEFAULT_TIMEOUT SERVER_DEFAULT_TIMEOUT} (default) to rely on the server-side configured timeout.
192198
* <p>
193199
* This functionality allows to limit query/transaction execution time. Specified timeout overrides the default timeout configured in the database
194200
* using {@code dbms.transaction.timeout} setting.
195201
* <p>
196-
* Provided value should not be {@code null} and should not represent a duration of zero or negative duration.
202+
* Provided value should not represent a negative duration.
197203
*
198204
* @param timeout the timeout.
199205
* @return this builder.
200206
*/
201207
public Builder withTimeout( Duration timeout )
202208
{
203-
requireNonNull( timeout, "Transaction timeout should not be null" );
204-
checkArgument( !timeout.isZero(), "Transaction timeout should not be zero" );
205-
checkArgument( !timeout.isNegative(), "Transaction timeout should not be negative" );
209+
if (timeout != null)
210+
{
211+
checkArgument( !timeout.isNegative(), "Transaction timeout should not be negative" );
212+
}
206213

207214
this.timeout = timeout;
208215
return this;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package neo4j.org.testkit.backend;
2+
3+
public class CustomDriverError extends java.lang.RuntimeException
4+
{
5+
}

testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.netty.channel.Channel;
2222
import io.netty.channel.ChannelHandlerContext;
2323
import io.netty.channel.ChannelInboundHandlerAdapter;
24+
import neo4j.org.testkit.backend.CustomDriverError;
2425
import neo4j.org.testkit.backend.TestkitState;
2526
import neo4j.org.testkit.backend.messages.requests.TestkitRequest;
2627
import neo4j.org.testkit.backend.messages.responses.BackendError;
@@ -145,6 +146,20 @@ else if ( isConnectionPoolClosedException( throwable ) || throwable instanceof U
145146
)
146147
.build();
147148
}
149+
else if ( throwable instanceof CustomDriverError )
150+
{
151+
throwable = throwable.getCause();
152+
String id = testkitState.newId();
153+
return DriverError.builder()
154+
.data(
155+
DriverError.DriverErrorBody.builder()
156+
.id( id )
157+
.errorType( throwable.getClass().getName() )
158+
.msg( throwable.getMessage() )
159+
.build()
160+
)
161+
.build();
162+
}
148163
else
149164
{
150165
return BackendError.builder().data( BackendError.BackendErrorBody.builder().msg( throwable.toString() ).build() ).build();

testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import lombok.Getter;
2222
import lombok.Setter;
23+
import neo4j.org.testkit.backend.CustomDriverError;
2324
import neo4j.org.testkit.backend.TestkitState;
2425
import neo4j.org.testkit.backend.holder.AsyncTransactionHolder;
2526
import neo4j.org.testkit.backend.holder.RxTransactionHolder;
@@ -45,6 +46,30 @@ public class SessionBeginTransaction implements TestkitRequest
4546
{
4647
private SessionBeginTransactionBody data;
4748

49+
private void configureTimeout( TransactionConfig.Builder builder )
50+
{
51+
if ( data.getTimeoutPresent() )
52+
{
53+
try
54+
{
55+
if ( data.getTimeout() != null )
56+
{
57+
builder.withTimeout( Duration.ofMillis( data.getTimeout() ) );
58+
}
59+
else
60+
{
61+
builder.withTimeout( TransactionConfig.Builder.SERVER_DEFAULT_TIMEOUT );
62+
}
63+
}
64+
catch ( IllegalArgumentException e )
65+
{
66+
CustomDriverError wrapped = new CustomDriverError();
67+
wrapped.initCause( e );
68+
throw wrapped;
69+
}
70+
}
71+
}
72+
4873
@Override
4974
public TestkitResponse process( TestkitState testkitState )
5075
{
@@ -53,10 +78,7 @@ public TestkitResponse process( TestkitState testkitState )
5378
TransactionConfig.Builder builder = TransactionConfig.builder();
5479
Optional.ofNullable( data.txMeta ).ifPresent( builder::withMetadata );
5580

56-
if ( data.getTimeout() != null )
57-
{
58-
builder.withTimeout( Duration.ofMillis( data.getTimeout() ) );
59-
}
81+
configureTimeout( builder );
6082

6183
org.neo4j.driver.Transaction transaction = session.beginTransaction( builder.build() );
6284
return transaction( testkitState.addTransactionHolder( new TransactionHolder( sessionHolder, transaction ) ) );
@@ -72,10 +94,7 @@ public CompletionStage<TestkitResponse> processAsync( TestkitState testkitState
7294
TransactionConfig.Builder builder = TransactionConfig.builder();
7395
Optional.ofNullable( data.txMeta ).ifPresent( builder::withMetadata );
7496

75-
if ( data.getTimeout() != null )
76-
{
77-
builder.withTimeout( Duration.ofMillis( data.getTimeout() ) );
78-
}
97+
configureTimeout( builder );
7998

8099
return session.beginTransactionAsync( builder.build() ).thenApply( tx -> transaction(
81100
testkitState.addAsyncTransactionHolder( new AsyncTransactionHolder( sessionHolder, tx ) ) ) );
@@ -92,10 +111,7 @@ public Mono<TestkitResponse> processRx( TestkitState testkitState )
92111
TransactionConfig.Builder builder = TransactionConfig.builder();
93112
Optional.ofNullable( data.txMeta ).ifPresent( builder::withMetadata );
94113

95-
if ( data.getTimeout() != null )
96-
{
97-
builder.withTimeout( Duration.ofMillis( data.getTimeout() ) );
98-
}
114+
configureTimeout( builder );
99115

100116
return Mono.fromDirect( session.beginTransaction( builder.build() ) )
101117
.map( tx -> transaction(
@@ -108,12 +124,23 @@ private Transaction transaction( String txId )
108124
return Transaction.builder().data( Transaction.TransactionBody.builder().id( txId ).build() ).build();
109125
}
110126

111-
@Getter
112-
@Setter
113127
public static class SessionBeginTransactionBody
114128
{
129+
@Getter
130+
@Setter
115131
private String sessionId;
132+
@Getter
133+
@Setter
116134
private Map<String,Object> txMeta;
135+
@Getter
117136
private Integer timeout;
137+
@Getter
138+
private Boolean timeoutPresent = false;
139+
140+
public void setTimeout( Integer timeout )
141+
{
142+
this.timeout = timeout;
143+
timeoutPresent = true;
144+
}
118145
}
119146
}

testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2222
import lombok.Getter;
2323
import lombok.Setter;
24+
import neo4j.org.testkit.backend.CustomDriverError;
2425
import neo4j.org.testkit.backend.TestkitState;
2526
import neo4j.org.testkit.backend.holder.ResultCursorHolder;
2627
import neo4j.org.testkit.backend.holder.ResultHolder;
@@ -49,6 +50,30 @@ public class SessionRun implements TestkitRequest
4950
{
5051
private SessionRunBody data;
5152

53+
private void configureTimeout( TransactionConfig.Builder builder )
54+
{
55+
if ( data.getTimeoutPresent() )
56+
{
57+
try
58+
{
59+
if ( data.getTimeout() != null )
60+
{
61+
builder.withTimeout( Duration.ofMillis( data.getTimeout() ) );
62+
}
63+
else
64+
{
65+
builder.withTimeout( TransactionConfig.Builder.SERVER_DEFAULT_TIMEOUT );
66+
}
67+
}
68+
catch ( IllegalArgumentException e )
69+
{
70+
CustomDriverError wrapped = new CustomDriverError();
71+
wrapped.initCause( e );
72+
throw wrapped;
73+
}
74+
}
75+
}
76+
5277
@Override
5378
public TestkitResponse process( TestkitState testkitState )
5479
{
@@ -59,7 +84,7 @@ public TestkitResponse process( TestkitState testkitState )
5984
.orElseGet( () -> new Query( data.cypher ) );
6085
TransactionConfig.Builder transactionConfig = TransactionConfig.builder();
6186
Optional.ofNullable( data.getTxMeta() ).ifPresent( transactionConfig::withMetadata );
62-
Optional.ofNullable( data.getTimeout() ).ifPresent( to -> transactionConfig.withTimeout( Duration.ofMillis( to ) ) );
87+
configureTimeout( transactionConfig );
6388
org.neo4j.driver.Result result = session.run( query, transactionConfig.build() );
6489
String id = testkitState.addResultHolder( new ResultHolder( sessionHolder, result ) );
6590

@@ -78,8 +103,7 @@ public CompletionStage<TestkitResponse> processAsync( TestkitState testkitState
78103
.orElseGet( () -> new Query( data.cypher ) );
79104
TransactionConfig.Builder transactionConfig = TransactionConfig.builder();
80105
Optional.ofNullable( data.getTxMeta() ).ifPresent( transactionConfig::withMetadata );
81-
Optional.ofNullable( data.getTimeout() )
82-
.ifPresent( to -> transactionConfig.withTimeout( Duration.ofMillis( to ) ) );
106+
configureTimeout( transactionConfig );
83107

84108
return session.runAsync( query, transactionConfig.build() )
85109
.thenApply( resultCursor ->
@@ -103,7 +127,7 @@ public Mono<TestkitResponse> processRx( TestkitState testkitState )
103127
.orElseGet( () -> new Query( data.cypher ) );
104128
TransactionConfig.Builder transactionConfig = TransactionConfig.builder();
105129
Optional.ofNullable( data.getTxMeta() ).ifPresent( transactionConfig::withMetadata );
106-
Optional.ofNullable( data.getTimeout() ).ifPresent( to -> transactionConfig.withTimeout( Duration.ofMillis( to ) ) );
130+
configureTimeout( transactionConfig );
107131

108132
RxResult result = session.run( query, transactionConfig.build() );
109133
String id = testkitState.addRxResultHolder( new RxResultHolder( sessionHolder, result ) );
@@ -120,17 +144,32 @@ private Result createResponse( String resultId )
120144
return Result.builder().data( Result.ResultBody.builder().id( resultId ).build() ).build();
121145
}
122146

123-
@Setter
124-
@Getter
125147
public static class SessionRunBody
126148
{
127149
@JsonDeserialize( using = TestkitCypherParamDeserializer.class )
150+
@Setter
151+
@Getter
128152
private Map<String,Object> params;
129153

154+
@Setter
155+
@Getter
130156
private String sessionId;
157+
@Setter
158+
@Getter
131159
private String cypher;
160+
@Setter
161+
@Getter
132162
private Map<String,Object> txMeta;
163+
@Getter
133164
private Integer timeout;
165+
@Getter
166+
private Boolean timeoutPresent = false;
167+
168+
public void setTimeout( Integer timeout )
169+
{
170+
this.timeout = timeout;
171+
timeoutPresent = true;
172+
}
134173

135174
}
136175
}

0 commit comments

Comments
 (0)