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

Closed
harmnot opened this issue Sep 30, 2024 · 5 comments

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 :(

@isabelatkinson
Copy link
Contributor

Hi @harmnot, please see my comment on your previous issue: #1136 (comment)

Do you know where specifically in your code example your program is hanging?

Additionally, if you're generally blocking on the calls to async driver methods, it may be easier to use the sync API.

@harmnot
Copy link
Author

harmnot commented Oct 9, 2024

@isabelatkinson it is hanging on insert_one_transactional when i use it multiple times, it is really blocking and never get any response, also when I have multiple async find_one as well, it is blocking/hanging

is that any example how to use sync API ? https://docs.rs/mongodb/latest/mongodb/sync/index.html

@isabelatkinson
Copy link
Contributor

Apologies for the delay here - here is a guide for using the sync API, as well as the documentation for the sync module.

Copy link

github-actions bot commented Nov 2, 2024

There has not been any recent activity on this ticket, so we are marking it as stale. If we do not hear anything further from you, this issue will be automatically closed in one week.

@github-actions github-actions bot added the Stale label Nov 2, 2024
Copy link

There has not been any recent activity on this ticket, so we are closing it. Thanks for reaching out and please feel free to file a new issue if you have further questions.

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

No branches or pull requests

2 participants