From e732b64fa6881cf25fd353edff4fd76c839e0c8b Mon Sep 17 00:00:00 2001 From: Kjetil Orbekk Date: Thu, 24 Nov 2022 10:30:06 -0500 Subject: Fix race condition when creating initial table state --- server/src/play.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'server/src') diff --git a/server/src/play.rs b/server/src/play.rs index 01f4847..256392d 100644 --- a/server/src/play.rs +++ b/server/src/play.rs @@ -33,7 +33,7 @@ impl DbJournal { #[async_trait] impl Journal for DbJournal { async fn append(&mut self, seq: i64, payload: serde_json::Value) -> Result<(), BridgeError> { - query!( + let result = query!( r#" insert into object_journal (id, seq, payload) values ($1, $2, $3) @@ -43,7 +43,12 @@ impl Journal for DbJournal { payload, ) .execute(&self.db) - .await?; + .await; + if let Err(sqlx::Error::Database(e)) = result { + if e.constraint() == Some("journal_entry") { + return Err(BridgeError::JournalConflict(format!("{}", self.id), seq)); + } + } Ok(()) } @@ -81,12 +86,17 @@ impl Table { impl Table { pub async fn new(mut journal: J) -> Result { + let game = Self::init(&mut journal).await?; + Ok(Table { journal, game }) + } + + async fn init(journal: &mut J) -> Result { let game = GameState::Bidding { dealer: Player::East, deal: bridge_engine::deal(), }; journal.append(0, json!(game)).await?; - Ok(Table { journal, game }) + Ok(game) } pub async fn replay(mut journal: J) -> Result { @@ -99,12 +109,11 @@ impl Table { } pub async fn new_or_replay(mut journal: J) -> Result { - let games = journal.replay(0).await?; - if games.is_empty() { - return Self::new(journal).await; + let game = Self::init(&mut journal).await; + if let Err(BridgeError::JournalConflict(..)) = game { + return Self::replay(journal).await; } - let game = serde_json::from_value(games[games.len() - 1].clone())?; - Ok(Table { journal, game } ) + Ok(Self { journal, game: game? } ) } } -- cgit v1.2.3