-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add durations to connection pool events #1166
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
Changes from all commits
bbee638
9989a43
f2c77c1
83a703b
6f93086
d5437f2
8ca8ab2
981c91d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,8 +16,12 @@ | |
|
||
package com.mongodb.event; | ||
|
||
import com.mongodb.connection.ConnectionPoolSettings; | ||
import com.mongodb.connection.ServerId; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
import static com.mongodb.assertions.Assertions.isTrueArgument; | ||
import static com.mongodb.assertions.Assertions.notNull; | ||
|
||
/** | ||
|
@@ -54,8 +58,25 @@ public enum Reason { | |
|
||
private final ServerId serverId; | ||
private final long operationId; | ||
|
||
private final Reason reason; | ||
private final long elapsedTimeNanos; | ||
|
||
/** | ||
* Constructs an instance. | ||
* | ||
* @param serverId The server ID. See {@link #getServerId()}. | ||
* @param operationId The operation ID. See {@link #getOperationId()}. | ||
* @param reason The reason the connection check out failed. See {@link #getReason()}. | ||
* @param elapsedTimeNanos The time it took while trying to check out the connection. See {@link #getElapsedTime(TimeUnit)}. | ||
* @since 4.11 | ||
*/ | ||
public ConnectionCheckOutFailedEvent(final ServerId serverId, final long operationId, final Reason reason, final long elapsedTimeNanos) { | ||
this.serverId = notNull("serverId", serverId); | ||
this.operationId = operationId; | ||
this.reason = notNull("reason", reason); | ||
isTrueArgument("waited time is not negative", elapsedTimeNanos >= 0); | ||
this.elapsedTimeNanos = elapsedTimeNanos; | ||
} | ||
|
||
/** | ||
* Construct an instance | ||
|
@@ -64,11 +85,12 @@ public enum Reason { | |
* @param operationId the operation id | ||
* @param reason the reason the connection check out failed | ||
* @since 4.10 | ||
* @deprecated Prefer {@link ConnectionCheckOutFailedEvent#ConnectionCheckOutFailedEvent(ServerId, long, Reason, long)}. | ||
* If this constructor is used, then {@link #getElapsedTime(TimeUnit)} is 0. | ||
*/ | ||
@Deprecated | ||
public ConnectionCheckOutFailedEvent(final ServerId serverId, final long operationId, final Reason reason) { | ||
this.serverId = notNull("serverId", serverId); | ||
this.operationId = operationId; | ||
this.reason = notNull("reason", reason); | ||
this(serverId, operationId, reason, 0); | ||
} | ||
|
||
/** | ||
|
@@ -77,6 +99,7 @@ public ConnectionCheckOutFailedEvent(final ServerId serverId, final long operati | |
* @param serverId the server id | ||
* @param reason the reason the connection check out failed | ||
* @deprecated Prefer {@link #ConnectionCheckOutFailedEvent(ServerId, long, Reason)} | ||
* If this constructor is used, then {@link #getOperationId()} is -1. | ||
*/ | ||
@Deprecated | ||
public ConnectionCheckOutFailedEvent(final ServerId serverId, final Reason reason) { | ||
|
@@ -112,13 +135,35 @@ public Reason getReason() { | |
return reason; | ||
} | ||
|
||
/** | ||
* The time it took to check out the connection. | ||
* More specifically, the time elapsed between the {@link ConnectionCheckOutStartedEvent} emitted by the same checking out and this event. | ||
* <p> | ||
* Naturally, if a new connection was not {@linkplain ConnectionCreatedEvent created} | ||
* and {@linkplain ConnectionReadyEvent established} as part of checking out, | ||
* this duration is usually not greater than {@link ConnectionPoolSettings#getMaxWaitTime(TimeUnit)}, | ||
* but may occasionally be greater than that, because the driver does not provide hard real-time guarantees.</p> | ||
* <p> | ||
* This duration does not currently include the time to deliver the {@link ConnectionCheckOutStartedEvent}. | ||
* Subject to change.</p> | ||
Comment on lines
+147
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤷♂️ Maybe users will request for that, maybe something else I can't anticipate comes up. There is an opportunity to allow for a future change, and I prefer to take it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we say "Subject to change", it seems to negate the documented behaviour immediately preceding, since users cannot rely on it. This reminded me of
For any API we do not consider Beta, I think we should either avoid documenting anything that is subject to change (in cases where the external behaviour is trivial or irrelevant to users), or commit to a behaviour. My opinion is that committing is preferable, assuming it is reasonable for a user to ask "but does this include user code"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We could say "we don't provide any guarantees on whether this duration includes the time to deliver ...". Instead, we give users more information: we document the current behavior (which enables a user to understand why his
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Described behaviour is rightly taken by users to be part of the public API. Some public behaviour might be tentative ("subject to change"), but my view is that all such instances in the driver should be marked with The original wording was describing public behaviour, however, I believe you are proposing that we might instead state this behaviour but clarify that it is non-public. I don't think we (or others) should describe implementation details, especially without a compelling reason. Otherwise, we might include many internal hints and tips in our docs. So:
My opinion is that you made the right call in excluding user code, and that we should publicly commit to that behaviour. I do not mind merging and changing this later via tickets, if that is more convenient. |
||
* | ||
* @param timeUnit The time unit of the result. | ||
* {@link TimeUnit#convert(long, TimeUnit)} specifies how the conversion from nanoseconds to {@code timeUnit} is done. | ||
* @return The time it took to establish the connection. | ||
* @since 4.11 | ||
*/ | ||
public long getElapsedTime(final TimeUnit timeUnit) { | ||
return timeUnit.convert(elapsedTimeNanos, TimeUnit.NANOSECONDS); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "ConnectionCheckOutFailedEvent{" | ||
+ "server=" + serverId.getAddress() | ||
+ ", clusterId=" + serverId.getClusterId() | ||
+ ", operationId=" + operationId | ||
+ ", reason=" + reason | ||
+ ", elapsedTimeNanos=" + elapsedTimeNanos | ||
+ '}'; | ||
} | ||
} |
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.
Suggestion: If expanding out the defaults in the java docs then also include:
(This applies to all deprecated constructors with a default operation id)
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 deliberately did not specify anything about
getElapsedTime
when documenting this constructor. The idea is that when we deprecate a constructor and introduce a new one, we should only update the documentation for the deprecated constructor and write the documentation for the new one. The reason behind this approach is that we are not going to remember and update all previous constructors each time we introduce a new one, which will lead to weird inconsistent documentation.When we say
Prefer {@link ...(ServerId, long, Reason, long)}. If this constructor is used, then {@link #getElapsedTime(TimeUnit)} is 0.
, a reader sees that the only difference between the preferred constructor and the one he looks at is a single parameterelapsedTimeNanos
, and the documentation explains what value the current constructor uses given that it does not acceptelapsedTimeNanos
from a user.Similarly, when we say
Prefer {@link ...(ServerId, long, Reason)}. If this constructor is used, then {@link #getOperationId()} is -1.
, a reader sees that the only difference between the preferred constructor and the one he looks at is a single parameteroperationId
, and the documentation explains what value the current constructor uses given that it does not acceptoperationId
from a user.The same goes about the preferred constructors. When we introduce a new constructor, the preferred one specified in all previously deprecated constructors is not replaced with the new constructor. It stays unchanged, thus forming a chain of preference, that leads a reader from any constructor to a more and more preferred one. The chain ends with the non-deprecated constructor.
Given this description of the approach and the reason behind it (both are in bold above), do you still want the docs for all previous constructors to be updated when a new one is introduced?
Uh oh!
There was an error while loading. Please reload this page.
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 live with that 👍