-
Notifications
You must be signed in to change notification settings - Fork 884
CASSJAVA-97: Let users inject an ID for each request and write to the custom payload #2037
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 4.x
Are you sure you want to change the base?
Conversation
I did integration testing with C* OSS 5.0.2. @lukasz-antoniak helped me add a
Running this client app, I got 17:03:20.860 [s0-io-5] TRACE InFlightHandler - [s0|id: 0xeefaab65, L:/127.0.0.2:52389 - R:/127.0.0.2:9042] Writing 00-d51ed2012c1f31b4434f409e50294da9-25da248d0a23981c-00 on stream id 0
17:03:20.863 [s0-io-5] TRACE CqlRequestHandler$NodeResponseCallback - [00-d51ed2012c1f31b4434f409e50294da9-25da248d0a23981c-00] Request sent on [id: 0xeefaab65, L:/127.0.0.2:52389 - R:/127.0.0.2:9042]
17:03:20.864 [s0-io-5] TRACE CqlRequestHandler$NodeResponseCallback - [00-d51ed2012c1f31b4434f409e50294da9-25da248d0a23981c-00] Speculative execution policy returned -1, no next execution
17:03:20.877 [s0-io-5] DEBUG InFlightHandler - [s0|id: 0xeefaab65, L:/127.0.0.2:52389 - R:/127.0.0.2:9042] Got last response on in-flight stream id 0, completing and releasing
17:03:20.877 [s0-io-5] TRACE InFlightHandler - [s0|id: 0xeefaab65, L:/127.0.0.2:52389 - R:/127.0.0.2:9042] Releasing stream id 0
17:03:20.877 [s0-io-5] TRACE CqlRequestHandler$NodeResponseCallback - [00-d51ed2012c1f31b4434f409e50294da9-25da248d0a23981c-00] Got result, completing And the
The value |
...ava/com/datastax/oss/driver/internal/core/tracker/W3CContextDistributedTraceIdGenerator.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java
Outdated
Show resolved
Hide resolved
// We cannot do statement.getCustomPayload().put() because the default empty map is abstract | ||
// But this will create new Statement instance for every request. We might want to optimize | ||
// this | ||
Map<String, ByteBuffer> existingMap = new HashMap<>(statement.getCustomPayload()); |
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.
Statement
is by design immutable. Maybe a nicer way would be to create method StatementBuilder.from(Statement)
where you could create builder again based on statement. The code would look like: StatementBuilder.from(statement).addCustomPayload(...).build()
.
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 think you can copy just the payload, not the whole statement:
Map<String, ByteBuffer> customPayload = statement.getCustomPayload();
if (!this.customPayloadKey.isEmpty()) {
customPayload =
NullAllowingImmutableMap.<String, ByteBuffer>builder()
.putAll(customPayload)
.put(
this.customPayloadKey,
ByteBuffer.wrap(nodeRequestId.getBytes(StandardCharsets.UTF_8)))
.build();
}
Then modify line 307 like so:
channel
- .write(message, statement.isTracing(), statement.getCustomPayload(), nodeResponseCallback)
+ .write(message, statement.isTracing(), customPayload, nodeResponseCallback)
.addListener(nodeResponseCallback);
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.
This solves the concurrency problem, but it also means the subsequent setFinalError(statement...)
, NodeResponseCallback(statement,...)
, and RequestTracker invocations do not have the statement with the actual custom payload.
Map<String, ByteBuffer> existingMap = new HashMap<>(statement.getCustomPayload()); | ||
existingMap.put( | ||
this.customPayloadKey, ByteBuffer.wrap(nodeRequestId.getBytes(StandardCharsets.UTF_8))); | ||
statement = statement.setCustomPayload(existingMap); |
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.
Overriding custom payload here is not thread-safe. If client application executes the same statement instance multiple times concurrently (not a good use-case, but still possible), we do not guarantee how this map will be changed. Maybe indeed, there is no other way than make a shallow copy of the statement. Will think about it.
/**
* Sets the custom payload to use for execution.
*
* <p>All the driver's built-in statement implementations are immutable, and return a new instance
* from this method. However custom implementations may choose to be mutable and return the same
* instance.
*
* <p>Note that it's your responsibility to provide a thread-safe map. This can be achieved with a
* concurrent or immutable implementation, or by making it effectively immutable (meaning that
* it's never modified after being set on the statement).
*/
@NonNull
@CheckReturnValue
SelfT setCustomPayload(@NonNull Map<String, ByteBuffer> newCustomPayload);
core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java
Outdated
Show resolved
Hide resolved
...main/java/com/datastax/oss/driver/internal/core/tracker/UuidDistributedTraceIdGenerator.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/datastax/oss/driver/api/core/tracker/DistributedTraceIdGenerator.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/datastax/oss/driver/api/core/tracker/DistributedTraceIdGenerator.java
Outdated
Show resolved
Hide resolved
...test/java/com/datastax/oss/driver/internal/core/tracker/DistributedTraceIdGeneratorTest.java
Outdated
Show resolved
Hide resolved
try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { | ||
String query = "SELECT * FROM system.local"; | ||
ResultSet rs = session.execute(query); | ||
ByteBuffer id = rs.getExecutionInfo().getRequest().getCustomPayload().get("trace_key"); |
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.
how do you inject for individual CQL request though?
Did i miss this kind of 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.
I added a test "should_use_customized_request_id_generator". Do you think it answers your question?
* @param hashCode the hashcode of the CqlRequestHandler | ||
* @return a unique identifier for the session request | ||
*/ | ||
String getSessionRequestId(@NonNull Request statement, @NonNull String sessionName, int hashCode); |
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.
This interface seems a bit too connected to the default impl of RequestIdGenerator. It makes sense to pass the hash code of the relevant CqlRequestHandler given that implementation but is that parameter going to be generally usable?
I'd almost prefer to see the complete CqlRequestHandler passed here rather than just a hash code. That way if other implementers want to pull other values out of the handler (or even provider their own custom handlers with additional info available) they have an easy way to do so.
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.
This getSessionRequestId
is invoked in CqlRequestHandler
's constructor. If we pass the CqlRequestHandler
in, the object will not be initialized yet.
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.
Maybe we can rename the parameter to salt
(similar to cryptography, an integer that just provides uniqueness of IDs)?
* @return a unique identifier for the node request | ||
*/ | ||
String getNodeRequestId( | ||
@NonNull Request statement, @NonNull String sessionRequestId, int executionCount); |
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 I guess; execution count feels very tied to how the default request ID generator works. Is there a way we can generalize this a bit?
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 think that this parameter makes sense. Within one session, we can retry sending the same request due to retry policy.
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.
Sure, but that doesn't mean execution count is relevant to all implementations. It also begs the question of whether other things can/should be included for all implementations.
More generally, I'd argue it's inclusion here is primarily a function of the necessity of implementing the current log prefix as a request ID generator... which I'm not sure is a good idea (more on that elsewhere).
manual/core/request_id/README.md
Outdated
|
||
Usage: | ||
* Inject ID generator: set the desired `RequestIdGenerator` in `advanced.request-id.generator.class`. | ||
The default implementation generates the session request ID as `{session_name}|{hash_code}`, and node request ID as `{session_name}|{hash_code}|{execution_count}`. |
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 don't really explain what {hash_code}
or {execution_count}
mean here
# add the request id to the custom payload with the given key | ||
# if empty, the request id will not be added to the custom payload | ||
custom-payload-with-key = "" | ||
} |
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.
Style nit - elsewhere we have a space before the opening brace {
- Session request ID: an identifier for an entire session.execute() call | ||
- Node request ID: an identifier for the execution of a CQL statement against a particular node. There can be one or more node requests for a single session request, due to retries or speculative executions. |
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.
Retries and speculative executions are often against different nodes than the original request, might prefer another name here like "Request Attempt ID".
Currently the server has no way to know whether a given request is a retry, this feature could help us provide a metric for original requests vs. retries on the server, which would be pretty cool.
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 took the name "node request" v.s. "session request" from c# opentelemetry feature.
db.operation.name | The type name of the operation being executed. | Session_Request({RequestType}) for session level calls and Node_Request({RequestType}) for node level calls |
---|
And Lukasz's outstanding request tracker interface PR.
Do you think we should align with their naming?
* | ||
* <p>Value-type: {@link String} | ||
*/ | ||
REQUEST_ID_CUSTOM_PAYLOAD_KEY("advanced.request-id.custom-payload-with-key"); |
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.
(nit) naming: I find "custom-payload-key" clearer, you're already using that naming elsewhere
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.
Do you mean the enum name, or the typesafe config path?
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 believe @aratno is referring to the TypeSafe name @SiyaoIsHiding ... "custom-payload-key" rather than "custom-payload-with-key". Assuming that's correct I think he's on to something there.
} | ||
# add the request id to the custom payload with the given key | ||
# if empty, the request id will not be added to the custom payload | ||
custom-payload-with-key = "" |
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.
Is there a way to disable Request IDs altogether? Seems like at least three possible states are needed:
- Disabled Request IDs, no behavior changes on upgrade
- Request IDs in driver logs only, not propagated to the server
- Request IDs in driver logs and propagated to the server
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.
The existing driver has a built-in logic to generate the log prefix, which is the same logic as the DefaultRequestIdGenerator
. So your no.1 state is the same no.2 state, where the DefaultRequestIdGenerator
is used.
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'd actually collapse your second and third cases into one @aratno. I'd also specify the rule a bit differently:
If the client has configured a request ID generator we'll use that to generate a consistent request ID via the log prefix on the client side and the custom payload params delivered to the server. Otherwise we'll preserve the current log prefix on the client side and add nothing to the custom payload.
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'm on board with 2 + 3 being a single case, especially in the near-term, but 1 is different
} | ||
# add the request id to the custom payload with the given key | ||
# if empty, the request id will not be added to the custom payload | ||
custom-payload-with-key = "" |
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.
How would a user know what to set this to? Can we come up with a reasonable default that's more likely to be interoperable between C* protocol implementations (C*, Scylla, DSE / Astra, etc)?
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.
If we really need to choose one to recommend, I think we can recommend traceparent
, as it's specified in W3C context propagation protocol.
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.
Presumably this will vary with the implementation, right @aratno? Individaul C* request handlers might want to map this value to some name that makes sense for them. So I guess this would be very implementation-dependent... ?
Side note: it does raise an interesting question for Astra actually. We'd want to automatically set a request ID generator if the user is using Astra... but that's only half the problem. In addition to generating IDs in the expected format we'd also want to make sure the custom payload is being added at the right key for Astra. Hmmm... that's an interesting problem.
} | ||
String nodeRequestId = | ||
this.requestIdGenerator.getNodeRequestId(statement, logPrefix, currentExecutionIndex); | ||
if (!this.customPayloadKey.isEmpty()) { |
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 are not missing else
block here?
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.
Apologies all, I had to retreat to a cave for a bit and ponder some of the questions under consideration here as well as what was nagging me about the original API. I think I landed on a reasonable compromise that can be extended to address most (all?) of the outstanding concerns... but I'm not completely convinced of that yet. Comments welcomed/encouraged.
|
||
/** @return The driver's request ID generator; never {@code null}. */ | ||
@NonNull | ||
RequestIdGenerator getRequestIdGenerator(); |
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'm going to argue this should actually return Optional<RequestIdGenerator>
. I think part of the confusion for various other aspects of this ticket come down to (a) an impl which requires the driver to always have a request ID generator and (b) a confusion between a log prefix in the driver and what we're sending as a request ID.
* @return a unique identifier for the node request | ||
*/ | ||
String getNodeRequestId( | ||
@NonNull Request statement, @NonNull String sessionRequestId, int executionCount); |
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.
Sure, but that doesn't mean execution count is relevant to all implementations. It also begs the question of whether other things can/should be included for all implementations.
More generally, I'd argue it's inclusion here is primarily a function of the necessity of implementing the current log prefix as a request ID generator... which I'm not sure is a good idea (more on that elsewhere).
* @return a unique identifier for the node request | ||
*/ | ||
String getNodeRequestId( | ||
@NonNull Request statement, @NonNull String sessionRequestId, int executionCount); |
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.
In related news: how do we not include the node in question when we're generating a node request ID? Requests/Statements can have a node set as state but that's an optional thing a user can set in order to target a specific node; that's not automatically set for every request.
this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); | ||
this.requestIdGenerator = context.getRequestIdGenerator(); | ||
this.logPrefix = | ||
this.requestIdGenerator.getSessionRequestId(statement, sessionLogPrefix, this.hashCode()); |
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 think this is the root cause of my problem with the API. I think we need to clearly distinguish between a log prefix and a request ID. If a user doesn't configure a request ID generator that's totally fine... that means:
- Nothing is added to custom payload AND
- The old logic for generating a logPrefix is employed
That means our request ID generator API doesn't have to be retrofitted to support the existing log prefix syntax. It also resolve the issue @aratno has raised elsewhere, specifically "how do we shut this off if we don't want it?"
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.
This current implementation of request ID relies on the old log prefix implementation to propagate to other classes, like RequestLogger
and InFlightHandler
. If we separate request ID with log prefix, how do we propagate request ID?
.build(); | ||
// TODO: we are creating a new statement object for every request. We should optimize this. | ||
statement = statement.setCustomPayload(customPayload); | ||
} |
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.
This is the wrong place to do this. In most cases we haven't even selected the node yet; note that this happens immediately below where we poll the query plan if no node is explicitly set in the request. Assuming we update the request ID generation logic to correctly account for the target node the setting of custom payload fields should happen after we determine which node we're actually sending to.
} | ||
# add the request id to the custom payload with the given key | ||
# if empty, the request id will not be added to the custom payload | ||
custom-payload-with-key = "" |
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'd actually collapse your second and third cases into one @aratno. I'd also specify the rule a bit differently:
If the client has configured a request ID generator we'll use that to generate a consistent request ID via the log prefix on the client side and the custom payload params delivered to the server. Otherwise we'll preserve the current log prefix on the client side and add nothing to the custom payload.
} | ||
# add the request id to the custom payload with the given key | ||
# if empty, the request id will not be added to the custom payload | ||
custom-payload-with-key = "" |
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.
Presumably this will vary with the implementation, right @aratno? Individaul C* request handlers might want to map this value to some name that makes sense for them. So I guess this would be very implementation-dependent... ?
Side note: it does raise an interesting question for Astra actually. We'd want to automatically set a request ID generator if the user is using Astra... but that's only half the problem. In addition to generating IDs in the expected format we'd also want to make sure the custom payload is being added at the right key for Astra. Hmmm... that's an interesting problem.
* | ||
* <p>Value-type: {@link String} | ||
*/ | ||
REQUEST_ID_CUSTOM_PAYLOAD_KEY("advanced.request-id.custom-payload-with-key"); |
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 believe @aratno is referring to the TypeSafe name @SiyaoIsHiding ... "custom-payload-key" rather than "custom-payload-with-key". Assuming that's correct I think he's on to something there.
Updated to use Optional and delete DefaultRequestIdGenerator |
…ing logprefix behavior
…ution info does not have actual custom payload
c86e099
to
96ddaaa
Compare
core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java
Show resolved
Hide resolved
setFinalError(statement, AllNodesFailedException.fromErrors(this.errors), null, -1); | ||
} | ||
} else { | ||
String nodeLogPrefix; |
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.
Bret proposed: revert
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.
Revert to which version?
this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); | ||
this.requestIdGenerator = context.getRequestIdGenerator(); | ||
this.logPrefix = | ||
this.requestIdGenerator.isPresent() |
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.
Bret proposed:
this.logPrefix = sessionLogPrefix + "|" + (this.reqeustIdGenerator.isPresent() ? getSessionRequestID() : this.hashCode);
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.
The chief goal here is to represent the generated request ID as matching up to the CqlRequestHandler hash code but nothing else. Basically we want to use request ID to identify the handler only since (a) it's bound at that scale anyway and (b) the user can define their own session values.
core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java
Show resolved
Hide resolved
core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java
Show resolved
Hide resolved
|
||
this.startTimeNanos = System.nanoTime(); | ||
this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); | ||
this.requestIdGenerator = context.getRequestIdGenerator(); |
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.
If we provide default request ID generator implementation (that matches current log prefix), we will not need to do if-else statements to check if value is present.
this.requestIdGenerator = context.getRequestIdGenerator().orElse(new RequestIdGenerator() {
@Override
public String getSessionRequestId(@NonNull Request statement) {
return sessionLogPrefix + "|" + CqlRequestHandler.this.hashCode();
}
@Override
public String getNodeRequestId(@NonNull Request statement, @NonNull String sessionRequestId, int executionCount) {
return sessionRequestId;
}
});
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.
cc @absurdfarce, it seems like Bret doesn't like the idea of the default implementation because people would wonder how to turn off this feature
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.
To rephrase the answer from @SiyaoIsHiding just a bit... this gets to the point I was making about distinguishing between log prefix and the request ID generator. They aren't the same thing. They don't do the same thing. We always need a log prefix. But we aren't required to have a request ID generator. Trying to model log prefix as a request ID generator in all cases confuses those two roles.
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 think this conversation is largely resolved now. This code pretty clearly demonstrates that the simple use of the Optional type allows us to handle the default case in a more concise way. If anybody disagrees let's discuss further but given the current contents of the PR my inclination is to resolve this conversation as well.
In order to make this more concrete I've created a PR which clearly states my chief concerns for the current impl (as of this coment) and proposes a concrete implementation which I believe addresses them. This PR is made against a local version of the "request-traceability" branch from @SiyaoIsHiding 's original PR... it seemed like the easiest way to represent the proposed changes. I also include logging output from a small sample app using this code.... hopefully it clearly demonstrates the goal of these changes. |
… distinct entity (which keeps support for session names configured in the config) and (2) makes the request ID scoped by CqlRequestHandler.
After discussing the PR containing my proposed changes (referenced above) with @SiyaoIsHiding there seemed to be broad agreement on the structural changes (essentially decoupling the request ID from the session name and treating it as a replacement for the CqlRequestHandler hash code only) but some disagreement on method parameters and a few naming questions. In order to avoid fragmenting the discussion I've merged those changes into this PR (see this commit). We'll continue the discussion on these remaining points here. I'll be closing the alternate PR with a similar note shortly. |
* @param parentId the session request identifier | ||
* @return a unique identifier for the node request | ||
*/ | ||
String getRequestId(@NonNull Request statement, @NonNull String parentId); |
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.
Perhaps the single largest outstanding issue from the other PR: the naming of these methods. @SiyaoIsHiding has argued for "getSessionRequestId" and "getNodeRequestId" to maintain consistency with the C# interface (discussed in more detail in her comment elsewhere). I do not like either of these names, in no small part because the "session request ID" (a) isn't bound to the Session instance (and in fact the Session can have a completely different name) and (b) it's not actually used as an identifier for an outgoing message.
I'd argue that the names "getRequestId" and "getMessageId" are perhaps a bit clearer since they relate to what's actually going on. The request ID is associated with a single Request (which may in fact require multiple messages based on retries, speculative execution etc.) while the message ID is very clearly associated with a single message to a single node.
My intent with the names "getParentId" and "getRequestId" was to reinforce the parent-child relationship of these IDs but if we were really going to do that in a generic way this should probably have been "getParentId" and "getChildId"... and I agree that's kinda dumb. In the end I wound up going halfway with the parent-child thing with "getParentId" and the request/message split with "getRequestId" and the result is... just a mess.
I'm not sure what @lukasz-antoniak thinks. :)
I think I'm still arguing for getRequestId() and getMessageId(). I completely agree with @SiyaoIsHiding that we don't want to diverge from the public API for no reason but we're talking here about the API for request ID generators. I'm not expecting a huge number of new impls of this functionality, and even if we are the fact is the drivers represent discrete projects... and sometimes it may make more sense for the projects to diverge in naming if it's more sane for their impl.
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.
Bret covered my point above about aligning with the C# driver. An additional aspect is that our existing RequestTracker
interface is already using onSuccess
and onNodeSuccss
to differentiate the parent request v.s. the child. So using sessionRequest
and nodeRequest
aligns with the existing driver more.
Also, when we explain the 2 kinds of requests to the users, we say "one kind is the session.execute() call, another kind is the request that is sent to a node. One session.execute() can send multiple requests to the nodes due to retry and speculative executions." The words "session" and "node" have been in our explanation, that's where the naming "session request" and "node request" come from. Even if we use the wording request v.s. message, we still need to mention session.execute()
and "sent to a node" when explaining to our users.
I think the distinction "request" v.s. "message" is vague, because a lot of people also use the word "request" to describe the requests sent to a node. For example, when our DB team engineers talk about requests, they for sure mean the requests sent to the nodes instead of a session.execute()
call.
Also ping @aratno because Abe was also asking about the naming.
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.
cc @joao-r-reis because I think Joao came up with the naming "session request" and "node request" first
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 am with @SiyaoIsHiding on the method naming. Points from Bret are understandable and valid, but I think that we gain more consistency with "session request" and "node request". From what I see, Bret is mostly concerned about getSessionRequestId but if you read it as "get session-level request ID" I think it makes sense. RequestTracker
interface already introduces the naming of "node request", so the parent to that could be "session request".
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 think Session Request and Node Request are easier to explain to users in the context of the request tracker API but I do admit there wasn't a whole lot of discussion on these names when we went for these on the C# driver implementation. The java driver request tracker API docs refer to "node level" requests so making that leap to "Node Request" shouldn't be hard. I'd argue that "Message" is less clear since we don't have that name anywhere in the request tracker documentation AFAIK.
SessionRequest is not an ideal name but I didn't want it to just be "Request" since the "node level" request is called "Node Request". I wanted an additional qualifier so I went with "Session" but it could have been something different like "Parent Request" Idk
* | ||
* @return a unique identifier for the session request | ||
*/ | ||
String getParentId(); |
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.
A holdover question from the other PR: should we include a non-null Request here as well to keep the method calls consistent? I didn't do so since none of the current impls require such a parameter and it isn't immediately obvious to me that it's something that future impls might want to leverage. I don't want to add parameters just because somebody might need them someday. If we have a reasonable use case to suggest that there's something in the request other implementors might be interested in we can talk about that... but without a pretty clear idea there my default is to keep it out.
The other thing worth pointing out: if we're wrong and we start seeing lots of RequestIdGenerator impls in the wild we can always ask the community for feedback and/or expand the API. But I'd rather start with the minimal set of params we know we need right now and expand that set if there's a case to do so.
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 can agree to above statement. In any case we can add overloaded method signatures like in RequestTracker
.
if (programmaticArguments.getRequestIdGenerator() == null) { | ||
programmaticArgumentsBuilder.withRequestIdGenerator(new W3CContextRequestIdGenerator()); | ||
LOG.debug( | ||
"A secure connect bundle is provided, using W3CContextRequestIdGenerator as request ID generator."); |
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.
@absurdfarce the meeting today agreed that Astra will use traceparent
as the key. We should change the default key for Astra to traceparent
. It is request-id
right now.
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.
Agreed we should update to match the requirement for the Astra case @SiyaoIsHiding but I don't think we need to change the default in RequestIdGenerator. We should be able to address that by updating W3CContextRequestIdGenerator constructors:
new W3CContextRequestIdGenerator() == use the default key
new W3CContextRequestIdGenerator(String key) == use the provided key
Here we're in the Astra case so we'd clearly want to provide an arg.
Remember, W3CContextRequestidGenerator != AstraRequestIdGenerator. Just because the Astra requirements change doesn't mean we change the defaults.
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.
Bret and Andy and Jane agreed in the Sep 22 meeting that we will change the default key to traceparent
and allow override
No description provided.