-
Notifications
You must be signed in to change notification settings - Fork 21
Implement and test configurable transaction timeouts #197
Implement and test configurable transaction timeouts #197
Conversation
7eca957
to
929d7f8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still want to see if I can reduce size of package.lock diff... or is it ok that's 14k lines change?? Manually updated yarn.lock because i didn't want a 10k differ there too :(
update: done!
@@ -33,6 +33,7 @@ namespace Opts { | |||
prefetchSize?: number; | |||
prefetch?: boolean; | |||
sessionIdleTimeoutMillis?: number; | |||
transactionTimeoutMillis?: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new transaction option: millis before timeout
get transactionTimeoutMillis() { | ||
return this._transactionTimeoutMillis; | ||
} | ||
|
||
set transactionTimeoutMillis(millis: number) { | ||
if (millis < 1) { | ||
throw new TypeDBClientError(NEGATIVE_VALUE_NOT_ALLOWED.message(millis)); | ||
} | ||
this._sessionIdleTimeoutMillis = value; | ||
this._transactionTimeoutMillis = millis; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setter/getter for transaction timeouts
common/errors/ErrorMessage.ts
Outdated
export const CLUSTER_TOKEN_CREDENTIAL_INVALID = new Client(16, (args: Stringable[]) => `Invalid token credential.`); | ||
export const CLUSTER_INVALID_ROOT_CA_PATH = new Client(17, (args: Stringable[]) => `The provided Root CA path '${args[0]}' does not exist`); | ||
export const UNRECOGNISED_SESSION_TYPE = new Client(18, (args: Stringable[]) => `Session type '${args[0]}' was not recognised.`); | ||
export const TRANSACTION_CLOSED_WITH_ERRORS = new Client(4, (args) => `The transaction has been closed with error(s): \n${args[0]}.`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new exception to report a transaction is closed with errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for consistency with other constants in this file let's add the type annotation of args
:
export const TRANSACTION_CLOSED_WITH_ERRORS = new Client(4, (args) => `The transaction has been closed with error(s): \n${args[0]}.`) | |
export const TRANSACTION_CLOSED_WITH_ERRORS = new Client(4, (args: Stringable[]) => `The transaction has been closed with error(s): \n${args[0]}.`) |
import {Transaction} from "typedb-protocol/common/transaction_pb"; | ||
import {ConceptManager} from "../api/concept/ConceptManager"; | ||
import {TypeDBOptions} from "../api/connection/TypeDBOptions"; | ||
import {TransactionType, TypeDBTransaction} from "../api/connection/TypeDBTransaction"; | ||
import {LogicManager} from "../api/logic/LogicManager"; | ||
import {QueryManager} from "../api/query/QueryManager"; | ||
import {ErrorMessage} from "../common/errors/ErrorMessage"; | ||
import {TypeDBClientError} from "../common/errors/TypeDBClientError"; | ||
import {RequestBuilder} from "../common/rpc/RequestBuilder"; | ||
import {Stream} from "../common/util/Stream"; | ||
import {ConceptManagerImpl} from "../concept/ConceptManagerImpl"; | ||
import {LogicManagerImpl} from "../logic/LogicManagerImpl"; | ||
import {QueryManagerImpl} from "../query/QueryManagerImpl"; | ||
import {BidirectionalStream} from "../stream/BidirectionalStream"; | ||
import {TypeDBSessionImpl} from "./TypeDBSessionImpl"; | ||
import assert = require("assert"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto format....
connection/TypeDBTransactionImpl.ts
Outdated
private throwTransactionClosed(): void { | ||
assert(!this.isOpen()); | ||
const errors = this._bidirectionalStream.getErrors(); | ||
if (errors.length == 0) throw new TypeDBClientError(TRANSACTION_CLOSED); | ||
else throw new TypeDBClientError(TRANSACTION_CLOSED_WITH_ERRORS.message(errors)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can differentiate between a transaction closed with errors and one without errors
Before(async () => { | ||
before(); | ||
setSessionOptions(TypeDBOptions.cluster({"infer": true})); | ||
setTransactionOptions(TypeDBOptions.cluster({"infer": true})); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
initialising a cluster scenario involves the normal before()
and then setting various session/transaction options we always have on
Before(async () => { | ||
before(); | ||
setSessionOptions(TypeDBOptions.core({"infer": true})); | ||
setTransactionOptions(TypeDBOptions.core({"infer": true})); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same thing here
setTransactionOptions(TypeDBOptions.cluster({"infer": true})); | ||
}); | ||
|
||
After(async () => after()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for symmetry we also call the after()
in the ConnectionStepsBase.ts
class here
Given('set session option {word} to: {word}', async function (option: string, value: string) { | ||
if (!(option in optionSetters)) { | ||
throw ("Unrecognised option: " + option); | ||
} else { | ||
optionSetters[option](sessionOptions, value); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setter for connection options
@@ -48,7 +48,7 @@ echo Successfully unarchived TypeDB $PRODUCT distribution. | |||
echo Starting TypeDB $PRODUCT Server | |||
mkdir ./typedb-distribution/"$DIRECTORY"/typedb_test | |||
if [[ $PRODUCT == "Core" ]]; then | |||
./typedb-distribution/"$DIRECTORY"/typedb server --data typedb_test & | |||
./typedb-distribution/"$DIRECTORY"/typedb server --storage.data typedb_test & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new test server argument format!
@@ -79,6 +79,7 @@ behaviour_steps_common = [ | |||
"//test/behaviour/connection/session:SessionSteps.ts", | |||
"//test/behaviour/connection/transaction:TransactionSteps.ts", | |||
"//test/behaviour/typeql:TypeQLSteps.ts", | |||
"//test/behaviour/util:UtilSteps.ts", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
following other clients' we extract the wait
steps into their own UtilSteps
file
common/errors/ErrorMessage.ts
Outdated
export const CLUSTER_TOKEN_CREDENTIAL_INVALID = new Client(16, (args: Stringable[]) => `Invalid token credential.`); | ||
export const CLUSTER_INVALID_ROOT_CA_PATH = new Client(17, (args: Stringable[]) => `The provided Root CA path '${args[0]}' does not exist`); | ||
export const UNRECOGNISED_SESSION_TYPE = new Client(18, (args: Stringable[]) => `Session type '${args[0]}' was not recognised.`); | ||
export const TRANSACTION_CLOSED_WITH_ERRORS = new Client(4, (args) => `The transaction has been closed with error(s): \n${args[0]}.`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for consistency with other constants in this file let's add the type annotation of args
:
export const TRANSACTION_CLOSED_WITH_ERRORS = new Client(4, (args) => `The transaction has been closed with error(s): \n${args[0]}.`) | |
export const TRANSACTION_CLOSED_WITH_ERRORS = new Client(4, (args: Stringable[]) => `The transaction has been closed with error(s): \n${args[0]}.`) |
import {QueryManagerImpl} from "../query/QueryManagerImpl"; | ||
import {BidirectionalStream} from "../stream/BidirectionalStream"; | ||
import {TypeDBSessionImpl} from "./TypeDBSessionImpl"; | ||
import assert = require("assert"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've never used assert
before in Client NodeJS's production code.
Unlike in Java, there is no clean way to turn off assertions in NodeJS. (Methods typically used include hot module replacement - literally stripping the statements out of the source code before running it - and modifying the assert
prototype to replace assert
with a no-op function at runtime!)
I think we're better off replacing it with throw new TypeDBClientError
. We've done this elsewhere (see TypeDBClientImpl.session
which throws a Client NodeJS-only error if the session ID already exists).
} | ||
} | ||
else if (element.isDone() && !this._error) throw new TypeDBClientError(TRANSACTION_CLOSED); | ||
else if (element.isDone() && this._error) throw new TypeDBClientError(TRANSACTION_CLOSED_WITH_ERRORS.message(this._error)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember this came up in conversation: did we agree to leave the error there even after reading it for the first time? (seems like the right thing to do, just confirming intent)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep we did!
|
||
BeforeAll(async () => { | ||
setClient(await TypeDB.clusterClient([TypeDB.DEFAULT_ADDRESS], new TypeDBCredential("admin", "password", process.env.ROOT_CA))); | ||
}); | ||
|
||
Before(async () => { | ||
before(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're emulating inheritance here. The Cucumber structure doesn't allow for actual inheritance because it's based on top-level functions, not class functions.
So it might be clearer to call these methods beforeBase
and afterBase
. It makes it more obvious that they are only a partial implementation of Before
- the equivalent of calling super()
in Java (or JS).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can do!
load("@vaticle_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") | ||
|
||
exports_files(["Util.ts", "UtilSteps.ts"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I wonder if it's weird having a Util
and a UtilSteps
in the same package, given that (almost) every other package in behaviour
contains only one .ts
file, namely <packageName>Steps.ts
.
Might be ok!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eh this is how it is in the other client's i'm keeping it!
b496285
to
c994ed9
Compare
d0ff562
to
d0f135f
Compare
## What is the goal of this PR? We align with Client NodeJS version 2.6.1 (some of the work in typedb/typedb-driver-nodejs#197), which implements a better error propagation mechanism: when an exception occurs, we store it against all the transaction's active transmit queues to retrieve whenever the user tries to perform an operation in the transaction anywhere. ## What are the changes implemented in this PR? * store errors received from gRPC against each receive queue * return a new exception type, transaction is closed with errors, which throws the errors from all queues (note that this can be duplicate if there are multiple open transmit queues that have been given the same error) * we clean up queues that are no longer needed, so we minimise the number of times the user sees the same exception
## What is the goal of this PR? We align with Client NodeJS version 2.6.1 (mostly the work in typedb/typedb-driver-nodejs#197), which implements a better error propagation mechanism: when an exception occurs, we store it against all the transaction's active transmit queues to retrieve whenever the user tries to perform an operation in the transaction anywhere, ensuring the user always sees the originating error. ## What are the changes implemented in this PR? * store errors received from gRPC against each receive queue * return a new exception type, `transaction is closed with errors`, which throws the errors from all queues (note that this can be duplicate if there are multiple open transmit queues that have been given the same error) * we clean up queues that are no longer needed, so we minimise the number of times the user sees the same exception * update terminology around `ResponseCollector`, calling internal collectors `response_queues` instead of `collectors` (a collector made of collectors is a bit strange)
What is the goal of this PR?
Transactions now have a transaction timeouts, which are configurable via transaction options (typedb/typedb#6487). We implemented the new transaction option, and test them via new BDD scenarios. This also caused us to simplify and make more obvious when transaction errors occur when using an open transaction.
What are the changes implemented in this PR?
await
class to various test steps in BDD, plus importantly make theclose()
methods have the right asyncronous/promise signature that ensures users wanting to close() will know toawait
as well.