Files
movies-diary/crates/adapters/sqlite/src/migrations.rs

35 lines
1.2 KiB
Rust

use std::time::Duration;
use domain::errors::DomainError;
use sqlx::SqlitePool;
/// Server and worker both migrate at startup, so two processes can race on the
/// same database. The loser's migration fails (e.g. duplicate column) because
/// the winner already applied it; re-running re-reads `_sqlx_migrations` and
/// skips what is done. Only an error that persists across all retries is returned.
const RETRY_BACKOFFS: [Duration; 5] = [
Duration::from_millis(100),
Duration::from_millis(250),
Duration::from_millis(500),
Duration::from_secs(1),
Duration::from_secs(1),
];
pub(crate) async fn run(pool: &SqlitePool) -> Result<(), DomainError> {
let mut migrator = sqlx::migrate!("./migrations");
migrator.set_ignore_missing(true);
let mut backoffs = RETRY_BACKOFFS.iter();
loop {
match migrator.run(pool).await {
Ok(()) => return Ok(()),
Err(e) => match backoffs.next() {
Some(delay) => {
tracing::warn!("migration failed, retrying (concurrent migrator?): {e}");
tokio::time::sleep(*delay).await;
}
None => return Err(DomainError::InfrastructureError(e.to_string())),
},
}
}
}