Skip to content
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

using transaction got hang when if there is an error from database , and all read data got hang also forever #1210

Open
harmnot opened this issue Sep 30, 2024 · 0 comments
Assignees
Labels

Comments

@harmnot
Copy link

harmnot commented Sep 30, 2024

Versions/Environment

  1. What version of Rust are you using? rustup 1.27.1 (54dd3d00f 2024-04-24)
  2. What operating system are you using? OS X - Sonoma 14.4.1
  3. What versions of the driver and its dependencies are you using? registry+https://github.com/rust-lang/crates.io-index#[email protected] and registry+https://github.com/rust-lang/crates.io-index#[email protected]
  4. What version of MongoDB are you using? Mongo Atlas 7.0.12 Shared( free tier )
  5. 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 : #1136 , I thought it solved, it still happened now :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants