diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-11-24 10:30:06 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-11-24 10:30:24 -0500 |
commit | e732b64fa6881cf25fd353edff4fd76c839e0c8b (patch) | |
tree | fc3b4253c5dfdee717e333810a9dda2e5e78f937 | |
parent | 8fbf71b667d8b02777361adb7189939bd2d6fd02 (diff) |
Fix race condition when creating initial table state
-rw-r--r-- | server/src/play.rs | 25 |
1 files changed, 17 insertions, 8 deletions
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<J: Journal> Table<J> { impl<J: Journal> Table<J> { pub async fn new(mut journal: J) -> Result<Self, BridgeError> { + let game = Self::init(&mut journal).await?; + Ok(Table { journal, game }) + } + + async fn init(journal: &mut J) -> Result<GameState, BridgeError> { 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<Self, BridgeError> { @@ -99,12 +109,11 @@ impl<J: Journal> Table<J> { } pub async fn new_or_replay(mut journal: J) -> Result<Self, BridgeError> { - 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? } ) } } |