Select search mode

 
50 of 611

Fix generated timestamp on retry

Description

Hello ,

This is a duplicate of Github #438 for reference.

There is an issue with timestamps generated by timestamp generators in DefaultExecutionOptions.
No matter if the request is prepared or not, any retry, including speculative execution, will generate a new timestamp for the query when starting a new execution for the same request object.

As interpreted by Cassandra, the latest timestamp take precedence. Then, queries executed and marked as successful can be overwritten by past queries when retrying the execution.

The user feels that it is a retry but in fact, it is a new query.

This is done by the WriteQueue when calling request.write(...) which call writeQueryParameters(...) and then getOrGenerateTimestamp() which always generate a new timestamp for each new execution. It should generate one and use it for each consecutive calls to make a retry operation in Cassandra.

I did not write any tests for this change since I don't have a proper setup and configuration on my side which cause tests to fail. I think testing on the client side only, like this is enough:

Thank you very much,
Have a good day,

Luc

Environment

None

Pull Requests

https://github.com/datastax/nodejs-driver/pull/438

Fix versions

None

Details

Assignee

Reporter

Pull Request

Original estimate

Time tracking

No time logged15m remaining

Priority

Created April 26, 2025 at 8:51 AM
Updated 2 days ago

Activity

Bret McGuire 2 days ago

I think you’re on to something but I think we need to implement a fix at a different spot in the driver.

 

I’ll take a step back to explain my reasoning. Let’s look at a couple other drivers by way of comparison. The 4.x Java driver retry policy returns the request to be used on retry, although by default this is just the original request. The Python driver does something very similar. They’re able to do this because the driver (a) implements a “handler” object which governs the flow of a given request through it’s lifecycle and (b) maintains the message being sent as state within that handler… and this state includes the request timestamp. The Java driver manages request flow (including retries and speculative executions) via CqlRequestHandler while the message (and it’s timestamp) are represented as a discrete Java object (see the query message as an example). Python does something similar with different constructs; the ResponseFuture returned by exeucteX() calls manages the request lifecycle while request messages (and their timestamps) are encapsulated in Python objects.

 

The node.js driver does something similar… with an exception that’s pretty relevant to this discussion. There is a common request flow in RequestExecution. This logic looks very similar to the Java and Python examples but note that the stateful request contained here comes from the parent object, a RequestHandler. That request is created within Client but the crucial thing here is that it doesn’t track the request timetsamp. The serialization logic for that request is perfectly fine to let the timestamp be computed by the specified compute function… which gets into the logic you cite above.

 

It seems to me that the right way to fix this logic is to do something similar to what’s done in the other drivers and persist the timestamp as part of the underlying messages. I’d much rather make that change than modify how default timestamps are generated. This change shouldn’t have much of an impact on other driver functionality but we should definitely make sure we’re covered test-wise for any such change.

 

I’ll see if I can make this happen shortly… I completely agree with that the current behaviour is pretty clearly wrong on it’s face.

Bret McGuire April 27, 2025 at 8:55 PM

Thanks for the ticket and PR ! I’ll get these materials linked together and either or I will try to get a review for you shortly!

Flag notifications