work around race condition on community fetch (#3414)
authorphiresky <phireskyde+git@gmail.com>
Fri, 14 Jul 2023 12:57:36 +0000 (14:57 +0200)
committerGitHub <noreply@github.com>
Fri, 14 Jul 2023 12:57:36 +0000 (14:57 +0200)
crates/db_schema/src/impls/actor_language.rs

index 592d62a3045de872a76cc44ffc6dc697e728354e..eb68d2eea7082c004a151d58e7db01cc6e35abe4 100644 (file)
@@ -275,25 +275,37 @@ impl CommunityLanguage {
       return Ok(());
     }
 
+    let form = lang_ids
+      .into_iter()
+      .map(|language_id| CommunityLanguageForm {
+        community_id: for_community_id,
+        language_id,
+      })
+      .collect::<Vec<_>>();
+
     conn
       .build_transaction()
       .run(|conn| {
         Box::pin(async move {
           use crate::schema::community_language::dsl::{community_id, community_language};
+          use diesel::result::DatabaseErrorKind::UniqueViolation;
           // Clear the current languages
           delete(community_language.filter(community_id.eq(for_community_id)))
             .execute(conn)
             .await?;
 
-          for l in lang_ids {
-            let form = CommunityLanguageForm {
-              community_id: for_community_id,
-              language_id: l,
-            };
-            insert_into(community_language)
-              .values(form)
-              .get_result::<Self>(conn)
-              .await?;
+          let insert_res = insert_into(community_language)
+            .values(form)
+            .get_result::<Self>(conn)
+            .await;
+
+          if let Err(Error::DatabaseError(UniqueViolation, _info)) = insert_res {
+            // race condition: this function was probably called simultaneously from another caller. ignore error
+            // tracing::warn!("unique error: {_info:#?}");
+            // _info.constraint_name() should be = "community_language_community_id_language_id_key"
+            return Ok(());
+          } else {
+            insert_res?;
           }
           Ok(())
         }) as _