mongo-rust-driver
mongo-rust-driver copied to clipboard
using transaction got hang when if there is an error from database , and all read data got hang also forever
Versions/Environment
- What version of Rust are you using?
rustup 1.27.1 (54dd3d00f 2024-04-24)
- What operating system are you using?
OS X - Sonoma 14.4.1
- What versions of the driver and its dependencies are you using?
registry+https://github.com/rust-lang/crates.io-index#[email protected]
andregistry+https://github.com/rust-lang/crates.io-index#[email protected]
- What version of MongoDB are you using?
Mongo Atlas 7.0.12 Shared( free tier )
- What is your MongoDB topology (standalone, replica set, sharded cluster, serverless)?
sharded cluster
,
Describe the bug
I have a repository trait that use on services via transaction, here is my code
fn insert_one_transactional<P>(
&self,
mut params: InsertOneTransactionalParams<P>,
) -> Result<ResultInsertOneRepository, ErrorIdentifier>
where
P: DeserializeOwned + Unpin + Send + Sync + Serialize + Debug,
{
return executor::block_on(async {
let col = self.mongo.database.collection(params.col_name.to_owned().as_str());
if params.transactional.is_none() {
let session_result = self.mongo.client.start_session(None);
let session = match session_result.await {
Ok(session) => session,
Err(err) => {
return Err(ErrorIdentifier {
hint: HINT_KEY_WRITE_DATA.to_string(),
details: None,
code: ErrorGlobal::Repository,
message: err.to_string(),
});
}
};
params.transactional = Some(session);
match params.transactional.as_mut().unwrap().start_transaction(None).await {
Err(err) => {
// Handle the error here
return Err(self.process_error(err, params.col_name.to_owned()));
}
_ => {}
}
}
let result = col.insert_one_with_session(
params.doc,
params.options,
params.transactional.as_mut().unwrap(),
).await;
match result {
Ok(res) => {
Ok(ResultInsertOneRepository {
id: res.inserted_id.as_object_id().unwrap().to_hex(),
transactional: params.transactional.unwrap(),
})
}
Err(err) => {
return Err(self.process_error(err, params.col_name));
}
}
});
}
when I was using the function above on non looping case, it was works well, but when I have loop case which mutable the transactional, and then got error from db ( specially validation, I accidentally made it error to see the bug ) it was stuck / hang, I tried log in Err
but it was not received on there
is that any way to handle auto abort transactional without call abort_transaction() ? is that something wrong with code because I did wrong way to use that transaction ??
here how I use those function
fn handle_helper_function(&self, props: ParamsHandleCartSomething, mut trx: Transactional) -> Result<ResultHandleCartSomething, ErrorIdentifier> {
let mut sub_total = 0.0;
for (index, item) in props.custom_items.iter().enumerate() {
if item.quantity < 1 {
return Err(ErrorIdentifier {
code: ErrorGlobal::UseCase,
message: "Quantity must be greater than 0".to_string(),
details: None,
hint: "quantity_less_than_1_on_custom".to_string(),
});
}
for (_z_index, part) in item.parts.iter().enumerate() {
let product_part_data = self.service_product.get_one((part.to_owned().product_id, props.lang, false, None));
if let Err(e) = product_part_data {
return Err(e);
}
sub_total += price_product_val * item.quantity as f64;
let data_order_ipl = OrderPlaPla::<ProResponse> {
..Default::default()
};
let params_insert_order_pl = InsertOneTransactionalParams {
col_name: EnumCollectionModel::OrderPlaPla,
options: None,
doc: data_order_ipl.clone(),
transactional: Option::from(trx),
};
let result_order_ipl = self.repository.insert_one_transactional(params_insert_order_pl);
if let Err(e) = result_order_ipl {
return Err(e);
}
trx = result_order_ipl.unwrap().transactional;
}
let msr_id = DatabaseId::new();
let msr = YaYaYa {
..Default::default()
};
let params_insert_plapla = InsertOneTransactionalParams {
col_name: EnumCollectionModel::PlaPla,
options: None,
doc: msr.clone(),
transactional: Option::from(trx),
};
let result_plapla = self.repository.insert_one_transactional(params_insert_plapla);
if let Err(e) = result_plapla {
return Err(e);
}
trx = result_plapla.unwrap().transactional;
let data_order_blabla = OrderMeasurement {
..Default::default()
};
let params_insert_blabla = InsertOneTransactionalParams {
col_name: EnumCollectionModel::ColNameHere,
options: None,
doc: data_order_blabla.clone(),
transactional: Option::from(trx),
};
let result_order_blabla = self.repository.insert_one_transactional(params_insert_blabla);
if let Err(e) = result_order_blabla {
return Err(e);
}
trx = result_order_blabla.unwrap().transactional;
}
Ok(ResultHandleCartCustom {
trx,
sub_total,
})
}
at the end function above, I commit the transition like this IF not error ( but in fact the code not arrive on here yet , because the code above was bug )
pub fn commit_transaction(transactional: Option<Transactional>) -> Result<(), ErrorIdentifier> {
match transactional {
Some(mut transactional) => {
// Use block_on to run the future and get the result
let commit_result = block_on(async {
transactional.commit_transaction().await
});
match commit_result {
Ok(_) => {}
Err(e) => {
return Err(ErrorIdentifier {
code: ErrorGlobal::Repository,
message: e.to_string(),
hint: "error_transactional".to_string(),
details: None,
})
}
}
}
None => {}
}
Ok(())
}
I am using future
on my whole project
when I have transaction function insert_one_transactional
on looping, sometimes the MongoDB hang or keep loading, nothing give any response, when I cancel the request via postman and then try again , I got hang also and all read and other write clause are not working at all,
sometimes I got error like this
Kind: Command failed: Error code 112 (WriteConflict): Caused by :: :: Please retry your operation or multi-document transaction., labels: {\"TransientTransactionError\"}"
I believed something wrong with the transaction , I got stuck for few days only for this issue on my project :(
this was my issues also : https://github.com/mongodb/mongo-rust-driver/issues/1136 , I thought it solved, it still happened now :(