Page MenuHomePhabricator

D13568.diff
No OneTemporary

D13568.diff

diff --git a/services/identity/src/client_service.rs b/services/identity/src/client_service.rs
--- a/services/identity/src/client_service.rs
+++ b/services/identity/src/client_service.rs
@@ -17,7 +17,7 @@
use crate::database::{
DBDeviceTypeInt, DatabaseClient, DeviceType, KeyPayload, UserInfoAndPasswordFile,
};
-use crate::ddb_utils::Identifier;
+use crate::ddb_utils::{Identifier, is_transaction_conflict};
use crate::device_list::SignedDeviceList;
use crate::error::{DeviceListError, Error as DBError, consume_error};
use crate::grpc_services::authenticated::{DeletePasswordUserInfo, UpdatePasswordInfo};
@@ -1253,6 +1253,10 @@
| E::AwsSdk(DDBError::RequestLimitExceeded(_)) => {
Status::unavailable(msg::RETRY)
}
+ E::AwsSdk(ref err) if is_transaction_conflict(err) => {
+ warn!("DB operation conflicted. Returning RETRY status.");
+ Status::unavailable(msg::RETRY)
+ }
E::DeviceList(DeviceListError::InvalidDeviceListUpdate) => {
Status::invalid_argument(msg::INVALID_DEVICE_LIST_UPDATE)
}
diff --git a/services/identity/src/ddb_utils.rs b/services/identity/src/ddb_utils.rs
--- a/services/identity/src/ddb_utils.rs
+++ b/services/identity/src/ddb_utils.rs
@@ -9,12 +9,13 @@
},
database::{AttributeExtractor, AttributeMap},
};
+use once_cell::sync::Lazy;
use std::collections::{HashMap, HashSet};
use std::iter::IntoIterator;
use crate::{
constants::{
- USERS_TABLE_FARCASTER_ID_ATTRIBUTE_NAME,
+ retry, USERS_TABLE_FARCASTER_ID_ATTRIBUTE_NAME,
USERS_TABLE_SOCIAL_PROOF_ATTRIBUTE_NAME, USERS_TABLE_USERNAME_ATTRIBUTE,
USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE,
},
@@ -244,6 +245,27 @@
}
}
+/// There are two error codes for operation failure due to already ongoing
+/// transaction:
+/// - `DynamoDBError::TransactionConflict`
+/// - `DynamoDBError::TransactionCanceled` if `reason == "TransactionConflict"`
+///
+/// The former is thrown in case of normal write operation
+/// (WriteItem, UpdateItem, etc) when a transaction is modifying them
+/// at the moment.
+///
+/// The latter is thrown in transaction operation (TransactWriteItem) when
+/// another transaction is modifying them at the moment.
+pub fn is_transaction_conflict(err: &DynamoDBError) -> bool {
+ static RETRYABLE_CODES: Lazy<HashSet<&str>> =
+ Lazy::new(|| HashSet::from([retry::TRANSACTION_CONFLICT]));
+
+ match err {
+ DynamoDBError::TransactionConflictException(_) => true,
+ _ => is_transaction_retryable(err, &RETRYABLE_CODES),
+ }
+}
+
#[cfg(test)]
mod tests {
use crate::constants::one_time_keys_table;

File Metadata

Mime Type
text/plain
Expires
Thu, Oct 3, 8:55 AM (16 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2220795
Default Alt Text
D13568.diff (2 KB)

Event Timeline