Skip to content

Commit 034c3e7

Browse files
committed
Retry when encountering a network error establishing an initial connection to a server
1 parent b62936d commit 034c3e7

File tree

4 files changed

+104
-19
lines changed

4 files changed

+104
-19
lines changed

src/libmongoc/src/mongoc/mongoc-cluster.c

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,9 +2362,6 @@ mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster,
23622362
BSON_ASSERT (reply || true);
23632363
BSON_ASSERT (error || true);
23642364

2365-
mongoc_server_stream_t *server_stream = NULL;
2366-
bson_error_t err_local = {0};
2367-
23682365
ENTRY;
23692366

23702367
BSON_ASSERT (cluster);
@@ -2378,12 +2375,10 @@ mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster,
23782375
RETURN (NULL);
23792376
}
23802377

2381-
if (!error) {
2382-
error = &err_local;
2383-
}
23842378

2385-
server_stream = _mongoc_cluster_stream_for_server (
2386-
cluster, server_id, reconnect_ok, cs, reply, error);
2379+
mongoc_server_stream_t *const server_stream =
2380+
_mongoc_cluster_stream_for_server (
2381+
cluster, server_id, reconnect_ok, cs, reply, error);
23872382

23882383
if (_in_sharded_txn (cs)) {
23892384
_mongoc_client_session_pin (cs, server_id);
@@ -2801,6 +2796,7 @@ _mongoc_cluster_stream_for_optype (mongoc_cluster_t *cluster,
28012796
mongoc_ss_optype_t optype,
28022797
const mongoc_read_prefs_t *read_prefs,
28032798
mongoc_client_session_t *cs,
2799+
bool is_retryable,
28042800
bson_t *reply,
28052801
bson_error_t *error)
28062802
{
@@ -2844,14 +2840,73 @@ _mongoc_cluster_stream_for_optype (mongoc_cluster_t *cluster,
28442840
}
28452841
}
28462842

2847-
/* connect or reconnect to server if necessary */
2848-
server_stream = _mongoc_cluster_stream_for_server (
2849-
cluster, server_id, true /* reconnect_ok */, cs, reply, error);
2843+
bson_t first_reply;
2844+
bson_error_t first_error = {0};
2845+
2846+
server_stream = _mongoc_cluster_stream_for_server (cluster,
2847+
server_id,
2848+
true /* reconnect_ok */,
2849+
cs,
2850+
&first_reply,
2851+
&first_error);
2852+
28502853
if (server_stream) {
28512854
server_stream->must_use_primary = must_use_primary;
2855+
RETURN (server_stream);
28522856
}
28532857

2854-
RETURN (server_stream);
2858+
// Important: authentication errors are also considered retryable even if
2859+
// they not considered a network error.
2860+
const bool retryable_error = _mongoc_error_is_network (&first_error) ||
2861+
_mongoc_error_is_auth (&first_error);
2862+
2863+
if (is_retryable && retryable_error) {
2864+
bson_t retry_reply;
2865+
bson_error_t retry_error = {0};
2866+
2867+
server_stream =
2868+
_mongoc_cluster_stream_for_server (cluster,
2869+
server_id,
2870+
true /* reconnect_ok */,
2871+
cs,
2872+
&retry_reply,
2873+
&retry_error);
2874+
2875+
if (server_stream) {
2876+
server_stream->must_use_primary = must_use_primary;
2877+
server_stream->retry_attempted = true;
2878+
bson_destroy (&first_reply);
2879+
RETURN (server_stream);
2880+
}
2881+
2882+
if (optype != MONGOC_SS_READ) {
2883+
// Retryable Writes Spec: When the driver encounters a network error
2884+
// establishing an initial connection to a server, it MUST add a
2885+
// RetryableWriteError label to that error if the MongoClient
2886+
// performing the operation has the retryWrites configuration option
2887+
// set to true.
2888+
_mongoc_write_error_append_retryable_label (&first_reply);
2889+
}
2890+
2891+
bson_destroy (&retry_reply);
2892+
}
2893+
2894+
// Retryable Writes Spec: If the driver cannot select a server for the retry
2895+
// attempt [...], retrying is not possible and drivers MUST raise the
2896+
// original retryable error.
2897+
{
2898+
if (reply) {
2899+
bson_steal (reply, &first_reply);
2900+
} else {
2901+
bson_destroy (&first_reply);
2902+
}
2903+
2904+
if (error) {
2905+
*error = first_error;
2906+
}
2907+
}
2908+
2909+
RETURN (NULL);
28552910
}
28562911

28572912
mongoc_server_stream_t *
@@ -2864,8 +2919,14 @@ mongoc_cluster_stream_for_reads (mongoc_cluster_t *cluster,
28642919
const mongoc_read_prefs_t *const prefs_override =
28652920
_mongoc_client_session_in_txn (cs) ? cs->txn.opts.read_prefs : read_prefs;
28662921

2922+
// Retryable Reads Spec: This boolean option determines whether retryable
2923+
// behavior will be applied to all read operations executed within the
2924+
// MongoClient.
2925+
const bool is_retryable = mongoc_uri_get_option_as_bool (
2926+
cluster->uri, MONGOC_URI_RETRYREADS, MONGOC_DEFAULT_RETRYREADS);
2927+
28672928
return _mongoc_cluster_stream_for_optype (
2868-
cluster, MONGOC_SS_READ, prefs_override, cs, reply, error);
2929+
cluster, MONGOC_SS_READ, prefs_override, cs, is_retryable, reply, error);
28692930
}
28702931

28712932
mongoc_server_stream_t *
@@ -2874,8 +2935,11 @@ mongoc_cluster_stream_for_writes (mongoc_cluster_t *cluster,
28742935
bson_t *reply,
28752936
bson_error_t *error)
28762937
{
2938+
const bool is_retryable = mongoc_uri_get_option_as_bool (
2939+
cluster->uri, MONGOC_URI_RETRYWRITES, MONGOC_DEFAULT_RETRYWRITES);
2940+
28772941
return _mongoc_cluster_stream_for_optype (
2878-
cluster, MONGOC_SS_WRITE, NULL, cs, reply, error);
2942+
cluster, MONGOC_SS_WRITE, NULL, cs, is_retryable, reply, error);
28792943
}
28802944

28812945
mongoc_server_stream_t *
@@ -2889,10 +2953,14 @@ mongoc_cluster_stream_for_aggr_with_write (
28892953
const mongoc_read_prefs_t *const prefs_override =
28902954
_mongoc_client_session_in_txn (cs) ? cs->txn.opts.read_prefs : read_prefs;
28912955

2956+
const bool is_retryable = mongoc_uri_get_option_as_bool (
2957+
cluster->uri, MONGOC_URI_RETRYWRITES, MONGOC_DEFAULT_RETRYWRITES);
2958+
28922959
return _mongoc_cluster_stream_for_optype (cluster,
28932960
MONGOC_SS_AGGREGATE_WITH_WRITE,
28942961
prefs_override,
28952962
cs,
2963+
is_retryable,
28962964
reply,
28972965
error);
28982966
}

src/libmongoc/src/mongoc/mongoc-cmd.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,10 @@ _allow_txn_number (const mongoc_cmd_parts_t *parts,
707707
return false;
708708
}
709709

710+
if (server_stream->retry_attempted) {
711+
return false;
712+
}
713+
710714
if (server_stream->sd->max_wire_version < WIRE_VERSION_RETRY_WRITES) {
711715
return false;
712716
}
@@ -740,6 +744,10 @@ _is_retryable_write (const mongoc_cmd_parts_t *parts,
740744
return false;
741745
}
742746

747+
if (server_stream->retry_attempted) {
748+
return false;
749+
}
750+
743751
if (server_stream->sd->max_wire_version < WIRE_VERSION_RETRY_WRITES) {
744752
return false;
745753
}
@@ -777,6 +785,10 @@ _is_retryable_read (const mongoc_cmd_parts_t *parts,
777785
return false;
778786
}
779787

788+
if (server_stream->retry_attempted) {
789+
return false;
790+
}
791+
780792
if (server_stream->sd->max_wire_version < WIRE_VERSION_RETRY_READS) {
781793
return false;
782794
}

src/libmongoc/src/mongoc/mongoc-server-stream-private.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ BSON_BEGIN_DECLS
3131

3232
typedef struct _mongoc_server_stream_t {
3333
mongoc_topology_description_type_t topology_type;
34-
mongoc_server_description_t *sd; /* owned */
35-
bson_t cluster_time; /* owned */
36-
mongoc_stream_t *stream; /* borrowed */
37-
/** If the stream was created in a way that may have overwritten the user's
38-
* readPreference, we need to know if server selection forced that change. */
34+
mongoc_server_description_t *sd; // owned
35+
bson_t cluster_time; // owned
36+
mongoc_stream_t *stream; // borrowed
37+
// If the stream was created in a way that may have overwritten the user's
38+
// readPreference, we need to know if server selection forced that change.
3939
bool must_use_primary;
40+
// True if this server stream was acquired during a retry attempt triggered
41+
// by a network error establishing an initial connection. Used to avoid
42+
// further retry attempts.
43+
bool retry_attempted;
4044
} mongoc_server_stream_t;
4145

4246

src/libmongoc/src/mongoc/mongoc-server-stream.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ mongoc_server_stream_new (const mongoc_topology_description_t *td,
3838
server_stream->sd = sd; /* becomes owned */
3939
server_stream->stream = stream; /* merely borrowed */
4040
server_stream->must_use_primary = false;
41+
server_stream->retry_attempted = false;
4142

4243
return server_stream;
4344
}

0 commit comments

Comments
 (0)