-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add Client Metadata Update Support. #1708
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: main
Are you sure you want to change the base?
Conversation
JAVA-5854
JAVA-5854
dependencies { | ||
testImplementation(libs.assertj) | ||
} |
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.
AssertJ has been used in this PR and added to test-base as it is a useful library that could be shared across all modules.
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 decision to use a new assertion library seems like something that should be debated a bit more widely, rather than being brought in as part of a PR like this one. How important do you think it is to the assertions required for this PR?
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 agree that adopting a new assertion or testing approach should generally be a broader team decision. This isn’t a critical for this PR, so I can remove it from this PR. AssertJ has already been used in the Kotlin coroutine module (reference) and is present in the toml file, though it’s not widely used in the codebase. This PR made the library visible to all modules, based on its usefulness in the Hibernate repository, which was the motivation for extending its usage further.
For now, I will revert this change and we can revisit the discussion as a team.
JAVA-5854
JAVA-5854
JAVA-5854
JAVA-5854
JAVA-5854
JAVA-5870
JAVA-5870
JAVA-5870
JAVA-5870
JAVA-5870
JAVA-5870
JAVA-5870
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.
Initial feedback
driver-core/src/main/com/mongodb/internal/connection/ClientMetadata.java
Outdated
Show resolved
Hide resolved
JAVA-5870
JAVA-5870
# Conflicts: # driver-core/src/test/resources/specifications # driver-core/src/test/unit/com/mongodb/internal/connection/MultiServerClusterSpecification.groovy
# Conflicts: # driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java
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.
Not sure why the changes of SDAM/Connection/Monitoring is part of this PR? The client metadata aspect LGTM but didn't review the SDAM changes
@@ -269,7 +270,7 @@ private boolean handleReplicaSetMemberChanged(final ServerDescription newDescrip | |||
} | |||
|
|||
if (isStalePrimary(newDescription)) { | |||
invalidatePotentialPrimary(newDescription); | |||
invalidatePotentialPrimary(newDescription, new MongoStalePrimaryException("Primary marked stale due to electionId/setVersion mismatch")); |
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 test asserting this exception?
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.
Replied in #1708 (comment).
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.
why it show up empty in the diff?
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.
Replied in #1708 (comment).
dependencies { | ||
testImplementation(libs.assertj) | ||
} |
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 decision to use a new assertion library seems like something that should be debated a bit more widely, rather than being brought in as part of a PR like this one. How important do you think it is to the assertions required for this PR?
import java.util.concurrent.locks.ReentrantReadWriteLock; | ||
|
||
import static com.mongodb.internal.Locks.withLock; | ||
import static com.mongodb.internal.connection.ClientMetadataHelper.createClientMetadataDocument; |
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.
Now that we have a proper ClientMetadata
class that is meant to be instantiated, it seems like we no longer need a separate ClientMetadataHelper
class, instead moving the methods of that class into this one.
* <p> | ||
* Platform is appended separately to the existing platform if it does not exceed {@value MAXIMUM_CLIENT_METADATA_ENCODED_SIZE} bytes. | ||
*/ | ||
public static BsonDocument updateClientMetadataDocument(final BsonDocument clientMetadataDocument, |
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.
Let's consider a slightly different algorithm for updating client metadata that shared more logic with createClientMetadataDocument
.
Now that we have a ClientMetadata
class that is meant to be instantiated, we can store more than just the resulting BsonDocument
representing the metadata. We can also store the data from which it was created: the application name and the MongoDriverInformation
. If we have that, we can share all the create logic by first merging the original MongoDriverInformation
with the appended one, and then calling createClientMetadataDocument
. We might need a new MongoDriverInformation#merge
method, or it could be added to the MongoDriverInformation.Builder
, but otherwise it reduces the code complexity a bit.
What do you think?
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.
After our offline discussion, I checked the spec and see that we’re actually allowed to omit any values outside of client.driver
if the appended driver name, version, and platform take up the full space.
I agree that removing updateClientMetadata
makes code easier to reason about.
I’ve updated the code to reuse createClientMetadataDocument
, but I think we should avoid adding public API elements purely for internal purposes. To address that, I added an internal class to encapsulate the metadata construction logic - similar to what we did with SearchIndexRequest
as an internal representation of SearchIndexModel
.
I pushed a commit to a separate branch vbabanin@a41ad61. What do you think?
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 like the approach.
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 the changes to this PR in this commit: 66a5913. Thank you! Let me know if you have any further suggestions.
driver-core/src/main/com/mongodb/internal/connection/ClientMetadata.java
Outdated
Show resolved
Hide resolved
After merging main into this branch, some diffs (SDAM-related changes) are appearing, even though they’re already present on main and the total number of line additions hasn’t changed. I’m looking into why this is happening. |
@Override | ||
boolean isCurrentRuntimeContainer() { | ||
try { | ||
return Files.exists(get(File.separator + ".dockerenv")); |
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 file is not always guaranteed to be created. we can add other heuristics based on cgroup
and environment variables (set by Kubernetes for example)
boolean isRunningInContainer() {
// Check for /.dockerenv
if (Files.exists(Paths.get("/.dockerenv"))) return true;
// Check cgroup for Docker/container patterns
try {
List<String> lines = Files.readAllLines(Paths.get("/proc/1/cgroup"));
for (String line : lines) {
if (line.contains("docker") || line.contains("kubepods") || line.contains("containerd")) {
return true;
}
}
} catch (IOException ignored) {}
// Check for common container environment variable
if (System.getenv("container") != null) return true;
return false;
}
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.
Those are valid points and I agree. However, these changes were just moved from ClientMetadataHelper
to consolidate them in the ClientMetadata
instance; they were already present in the codebase and were not introduced in this PR.
You can see the diff here:
https://github.com/mongodb/mongo-java-driver/pull/1708/files#diff-ad857628989f20f23a2f410c3a2c9b49d1fc664d06a2998a489393adb5bd8e8dR161
The methods getOperatingSystemType
, getOperatingSystemName
, and nameStartsWith
were also moved from ClientMetadataHelper
. They show up as new additions because I relocated them to the bottom of the class for better organization - separating utility methods from the core logic.
} | ||
} | ||
}, | ||
UNKNOWN(null); |
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.
Are we interested to track other containers like Podman?
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.
Replied in #1708 (comment).
K8S("kubernetes") { | ||
@Override | ||
boolean isCurrentOrchestrator() { | ||
return FaasEnvironment.getEnv("KUBERNETES_SERVICE_HOST") != null; |
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 also check for /etc/kubernetes
per node if available?
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.
Replied in #1708 (comment).
.build(); | ||
} | ||
|
||
private static String listToString(final List<String> listOfStrings) { |
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't we use
String result = listOfStrings.stream()
.collect(Collectors.joining(SEPARATOR));
Instead of this method?
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.
Replied in #1708 (comment).
driver-core/src/main/com/mongodb/internal/connection/ClientMetadata.java
Show resolved
Hide resolved
...r-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/MongoClientImpl.java
Show resolved
Hide resolved
JAVA-5870
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.
LGTM!
Adding an additional (unnecessary) LGTM to show excitement for 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.
Nice 🎉 minor comments
builder.maxConnectionIdleTime(1, TimeUnit.MILLISECONDS)) | ||
.build())) { | ||
|
||
//TODO change get() to orElseThrow |
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 relevant?
updateClientMetadata(driverVersion, driverName, driverPlatform, mongoClient); | ||
|
||
//then | ||
//TODO change get() to orElseThrow |
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.
ditto
builder.maxConnectionIdleTime(1, TimeUnit.MILLISECONDS)) | ||
.build())) { | ||
|
||
//TODO change get() to orElseThrow |
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.
ditto
updateClientMetadata(driverVersion, driverName, driverPlatform, mongoClient); | ||
|
||
//then | ||
//TODO change get() to orElseThrow |
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.
ditto
.build())) { | ||
|
||
//when | ||
//TODO change get() to orElseThrow |
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.
ditto
@@ -723,6 +723,8 @@ private OperationResult executeOperation(final UnifiedTestContext context, final | |||
return clientEncryptionHelper.executeEncrypt(operation); | |||
case "decrypt": | |||
return clientEncryptionHelper.executeDecrypt(operation); | |||
case "appendMetadata": | |||
return crudHelper.executeUpdateClientMetadata(operation); |
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.
Currently, other drivers can't update their submodule deps on the sepc until they update their runner? or are they excluding the new client metadata tests?
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.
Other drivers can update their submodule dependencies, however they will have to skip/ignore the new client metadata tests in their test runner until after they implemented the relevant changes from the epic.
# Conflicts: # driver-core/src/test/resources/specifications
Description
This PR updates the Java sync and reactive-streams driver to support dynamic client metadata updates, enabling wrapping libraries and integrations to append metadata about themselves when they do not instantiate the
MongoClient
directly.JAVA-5870
NOTE BEFORE MERGING:
Remove a submodule link to a fork: #1708 (comment)