summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-11-24 10:30:06 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-11-24 10:30:24 -0500
commite732b64fa6881cf25fd353edff4fd76c839e0c8b (patch)
treefc3b4253c5dfdee717e333810a9dda2e5e78f937
parent8fbf71b667d8b02777361adb7189939bd2d6fd02 (diff)
Fix race condition when creating initial table state
-rw-r--r--server/src/play.rs25
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? } )
}
}