@@ -59,77 +59,113 @@ impl RetrySession for DefaultRetrySession {
5959 if request_info. consistency . is_serial ( ) {
6060 return RetryDecision :: DontRetry ;
6161 } ;
62+ // Do not remove this lint!
63+ // It's there for a reason - we don't want new variants
64+ // automatically fall under `_` pattern when they are introduced.
65+ #[ deny( clippy:: wildcard_enum_match_arm) ]
6266 match request_info. error {
63- // Basic errors - there are some problems on this node
64- // Retry on a different one if possible
65- RequestAttemptError :: BrokenConnectionError ( _)
66- | RequestAttemptError :: DbError ( DbError :: Overloaded , _)
67- | RequestAttemptError :: DbError ( DbError :: ServerError , _)
68- | RequestAttemptError :: DbError ( DbError :: TruncateError , _) => {
67+ // With connection broken, we don't know if request was executed.
68+ RequestAttemptError :: BrokenConnectionError ( _) => {
6969 if request_info. is_idempotent {
7070 RetryDecision :: RetryNextTarget ( None )
7171 } else {
7272 RetryDecision :: DontRetry
7373 }
7474 }
75- // Unavailable - the current node believes that not enough nodes
76- // are alive to satisfy specified consistency requirements.
77- // Maybe this node has network problems - try a different one.
78- // Perform at most one retry - it's unlikely that two nodes
79- // have network problems at the same time
80- RequestAttemptError :: DbError ( DbError :: Unavailable { .. } , _) => {
81- if !self . was_unavailable_retry {
82- self . was_unavailable_retry = true ;
83- RetryDecision :: RetryNextTarget ( None )
84- } else {
85- RetryDecision :: DontRetry
86- }
87- }
88- // ReadTimeout - coordinator didn't receive enough replies in time.
89- // Retry at most once and only if there were actually enough replies
90- // to satisfy consistency but they were all just checksums (data_present == false).
91- // This happens when the coordinator picked replicas that were overloaded/dying.
92- // Retried request should have some useful response because the node will detect
93- // that these replicas are dead.
94- RequestAttemptError :: DbError (
95- DbError :: ReadTimeout {
96- received,
97- required,
98- data_present,
99- ..
100- } ,
101- _,
102- ) => {
103- if !self . was_read_timeout_retry && received >= required && !* data_present {
104- self . was_read_timeout_retry = true ;
105- RetryDecision :: RetrySameTarget ( None )
106- } else {
107- RetryDecision :: DontRetry
108- }
109- }
110- // Write timeout - coordinator didn't receive enough replies in time.
111- // Retry at most once and only for BatchLog write.
112- // Coordinator probably didn't detect the nodes as dead.
113- // By the time we retry they should be detected as dead.
114- RequestAttemptError :: DbError ( DbError :: WriteTimeout { write_type, .. } , _) => {
115- if !self . was_write_timeout_retry
116- && request_info. is_idempotent
117- && * write_type == WriteType :: BatchLog
118- {
119- self . was_write_timeout_retry = true ;
120- RetryDecision :: RetrySameTarget ( None )
121- } else {
122- RetryDecision :: DontRetry
75+ // DbErrors
76+ RequestAttemptError :: DbError ( db_error, _) => {
77+ // Do not remove this lint!
78+ // It's there for a reason - we don't want new variants
79+ // automatically fall under `_` pattern when they are introduced.
80+ #[ deny( clippy:: wildcard_enum_match_arm) ]
81+ match db_error {
82+ // Basic errors - there are some problems on this node
83+ // Retry on a different one if possible
84+ DbError :: Overloaded | DbError :: ServerError | DbError :: TruncateError => {
85+ if request_info. is_idempotent {
86+ RetryDecision :: RetryNextTarget ( None )
87+ } else {
88+ RetryDecision :: DontRetry
89+ }
90+ }
91+ // Unavailable - the current node believes that not enough nodes
92+ // are alive to satisfy specified consistency requirements.
93+ // Maybe this node has network problems - try a different one.
94+ // Perform at most one retry - it's unlikely that two nodes
95+ // have network problems at the same time
96+ DbError :: Unavailable { .. } => {
97+ if !self . was_unavailable_retry {
98+ self . was_unavailable_retry = true ;
99+ RetryDecision :: RetryNextTarget ( None )
100+ } else {
101+ RetryDecision :: DontRetry
102+ }
103+ }
104+ // ReadTimeout - coordinator didn't receive enough replies in time.
105+ // Retry at most once and only if there were actually enough replies
106+ // to satisfy consistency but they were all just checksums (data_present == false).
107+ // This happens when the coordinator picked replicas that were overloaded/dying.
108+ // Retried request should have some useful response because the node will detect
109+ // that these replicas are dead.
110+ DbError :: ReadTimeout {
111+ received,
112+ required,
113+ data_present,
114+ ..
115+ } => {
116+ if !self . was_read_timeout_retry && received >= required && !* data_present {
117+ self . was_read_timeout_retry = true ;
118+ RetryDecision :: RetrySameTarget ( None )
119+ } else {
120+ RetryDecision :: DontRetry
121+ }
122+ }
123+ // Write timeout - coordinator didn't receive enough replies in time.
124+ // Retry at most once and only for BatchLog write.
125+ // Coordinator probably didn't detect the nodes as dead.
126+ // By the time we retry they should be detected as dead.
127+ DbError :: WriteTimeout { write_type, .. } => {
128+ if !self . was_write_timeout_retry
129+ && request_info. is_idempotent
130+ && * write_type == WriteType :: BatchLog
131+ {
132+ self . was_write_timeout_retry = true ;
133+ RetryDecision :: RetrySameTarget ( None )
134+ } else {
135+ RetryDecision :: DontRetry
136+ }
137+ }
138+ // The node is still bootstrapping it can't execute the request, we should try another one
139+ DbError :: IsBootstrapping => RetryDecision :: RetryNextTarget ( None ) ,
140+ // In all other cases propagate the error to the user
141+ DbError :: SyntaxError
142+ | DbError :: Invalid
143+ | DbError :: AlreadyExists { .. }
144+ | DbError :: FunctionFailure { .. }
145+ | DbError :: AuthenticationError
146+ | DbError :: Unauthorized
147+ | DbError :: ConfigError
148+ | DbError :: ReadFailure { .. }
149+ | DbError :: WriteFailure { .. }
150+ | DbError :: Unprepared { .. }
151+ | DbError :: ProtocolError
152+ | DbError :: RateLimitReached { .. }
153+ | DbError :: Other ( _)
154+ | _ => RetryDecision :: DontRetry ,
123155 }
124156 }
125- // The node is still bootstrapping it can't execute the request, we should try another one
126- RequestAttemptError :: DbError ( DbError :: IsBootstrapping , _) => {
127- RetryDecision :: RetryNextTarget ( None )
128- }
129157 // Connection to the contacted node is overloaded, try another one
130158 RequestAttemptError :: UnableToAllocStreamId => RetryDecision :: RetryNextTarget ( None ) ,
131159 // In all other cases propagate the error to the user
132- _ => RetryDecision :: DontRetry ,
160+ RequestAttemptError :: BodyExtensionsParseError ( _)
161+ | RequestAttemptError :: CqlErrorParseError ( _)
162+ | RequestAttemptError :: CqlRequestSerialization ( _)
163+ | RequestAttemptError :: CqlResultParseError ( _)
164+ | RequestAttemptError :: NonfinishedPagingState
165+ | RequestAttemptError :: RepreparedIdChanged { .. }
166+ | RequestAttemptError :: RepreparedIdMissingInBatch
167+ | RequestAttemptError :: SerializationError ( _)
168+ | RequestAttemptError :: UnexpectedResponse ( _) => RetryDecision :: DontRetry ,
133169 }
134170 }
135171
0 commit comments