-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Include error messages for stale primary #1714
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?
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright 2008-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.mongodb; | ||
|
||
/** | ||
* Exception thrown when a replica set primary is identified as a stale primary during Server Discovery and Monitoring (SDAM). | ||
* This occurs when a new primary is discovered, causing the previously known primary to be marked stale, typically during network | ||
* partitions or elections. | ||
* | ||
* @since 5.6 | ||
*/ | ||
public class MongoStalePrimaryException extends MongoException { | ||
|
||
/** | ||
* Construct an instance. | ||
* | ||
* @param message the exception message. | ||
*/ | ||
public MongoStalePrimaryException(final String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -22,6 +22,7 @@ | |||||||||
import com.mongodb.MongoSecurityException; | ||||||||||
import com.mongodb.MongoSocketException; | ||||||||||
import com.mongodb.MongoSocketReadTimeoutException; | ||||||||||
import com.mongodb.MongoStalePrimaryException; | ||||||||||
import com.mongodb.annotations.Immutable; | ||||||||||
import com.mongodb.annotations.ThreadSafe; | ||||||||||
import com.mongodb.connection.ServerDescription; | ||||||||||
|
@@ -43,6 +44,15 @@ | |||||||||
*/ | ||||||||||
@ThreadSafe | ||||||||||
interface SdamServerDescriptionManager { | ||||||||||
/** | ||||||||||
* Receives candidate {@link ServerDescription} from the monitoring activity. | ||||||||||
* | ||||||||||
* @param candidateDescription A {@link ServerDescription} that may or may not be applied | ||||||||||
* {@linkplain TopologyVersionHelper#newer(TopologyVersion, TopologyVersion) depending on} | ||||||||||
* its {@link ServerDescription#getTopologyVersion() topology version}. | ||||||||||
*/ | ||||||||||
void monitorUpdate(ServerDescription candidateDescription); | ||||||||||
|
||||||||||
/** | ||||||||||
* @param candidateDescription A {@link ServerDescription} that may or may not be applied | ||||||||||
* {@linkplain TopologyVersionHelper#newer(TopologyVersion, TopologyVersion) depending on} | ||||||||||
|
@@ -84,34 +94,17 @@ private SdamIssue(@Nullable final Throwable exception, final Context context) { | |||||||||
this.context = assertNotNull(context); | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* @see #unspecified(Context) | ||||||||||
*/ | ||||||||||
static SdamIssue specific(final Throwable exception, final Context context) { | ||||||||||
static SdamIssue of(final Throwable exception, final Context context) { | ||||||||||
return new SdamIssue(assertNotNull(exception), assertNotNull(context)); | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* @see #specific(Throwable, Context) | ||||||||||
*/ | ||||||||||
static SdamIssue unspecified(final Context context) { | ||||||||||
return new SdamIssue(null, assertNotNull(context)); | ||||||||||
} | ||||||||||
Comment on lines
-95
to
-99
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. Previously, an Lines 131 to 134 in 4f8217a
This behavior aligns with the following section of the SDAM specification:
The Relevant spec changes: |
||||||||||
|
||||||||||
/** | ||||||||||
* @return An exception if and only if this {@link SdamIssue} is {@linkplain #specific()}. | ||||||||||
* @return An exception that caused this {@link SdamIssue}. | ||||||||||
*/ | ||||||||||
Optional<Throwable> exception() { | ||||||||||
return Optional.ofNullable(exception); | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* @return {@code true} if and only if this {@link SdamIssue} has an exception {@linkplain #specific(Throwable, Context) specified}. | ||||||||||
*/ | ||||||||||
boolean specific() { | ||||||||||
return exception != null; | ||||||||||
} | ||||||||||
|
||||||||||
ServerDescription serverDescription() { | ||||||||||
return unknownConnectingServerDescription(context.serverId(), exception); | ||||||||||
} | ||||||||||
|
@@ -127,6 +120,10 @@ boolean relatedToStateChange() { | |||||||||
return exception instanceof MongoNotPrimaryException || exception instanceof MongoNodeIsRecoveringException; | ||||||||||
} | ||||||||||
|
||||||||||
boolean relatedToStalePrimary() { | ||||||||||
return exception instanceof MongoStalePrimaryException; | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* Represents a subset of {@link #relatedToStateChange()}. | ||||||||||
* | ||||||||||
|
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.
The original
update()
method performed two checks:Although the spec specifies handling only network and command errors, the implementation currently checks for any
Throwable
.These two behaviors conform to the spec requirements for server monitor behavior:
after a successful server check
.when a server check fails
.The
update()
method was invoked from two places:ServerMonitor
, which is expected and directly supports the server monitor responsibilities outlined in the spec.DefaultServer.resetToConnecting()
, which is used in one specific case:when an RSPrimary is discovered with a stale electionId/setVersion
. In that case,update()
was called to transition the server to anUNKNOWN
state. However, neither check (1 nor 2) was triggered, so the method merely updated the description.This approach worked until the introduction of a new change where the
RSPrimary with a stale electionId/setVersion
case began passing an explicit exception, which unintentionally triggered a side effect of connection pool invalidation.To address this and maintain separation of concerns, the logic has now been split:
monitorUpdate()
: now encapsulates the server monitor-specific logic (checks 1 and 2).update()
: is simplified to only update the description toUNKNOWN
(currently used for one specific case).