fix: WAL mode + busy_timeout for SQLite, fix rate limiter TOCTOU race
This commit is contained in:
@@ -48,7 +48,9 @@ async fn wire_dependencies() -> anyhow::Result<AppState> {
|
||||
let database_url = std::env::var("DATABASE_URL").context("DATABASE_URL must be set")?;
|
||||
let opts = SqliteConnectOptions::from_str(&database_url)
|
||||
.context("Invalid DATABASE_URL")?
|
||||
.create_if_missing(true);
|
||||
.create_if_missing(true)
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.busy_timeout(std::time::Duration::from_secs(5));
|
||||
let pool = SqlitePool::connect_with(opts)
|
||||
.await
|
||||
.context("Failed to connect to SQLite database")?;
|
||||
|
||||
@@ -35,14 +35,15 @@ impl RateLimiter {
|
||||
.unwrap_or_default()
|
||||
.as_secs()
|
||||
/ 60;
|
||||
let prev = self.window.load(Ordering::Relaxed);
|
||||
let prev = self.window.load(Ordering::Acquire);
|
||||
if now != prev {
|
||||
self.window.store(now, Ordering::Relaxed);
|
||||
self.count.store(1, Ordering::Relaxed);
|
||||
true
|
||||
} else {
|
||||
self.count.fetch_add(1, Ordering::Relaxed) + 1 <= self.limit
|
||||
// compare_exchange ensures only one thread wins the window reset
|
||||
if self.window.compare_exchange(prev, now, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
|
||||
self.count.store(1, Ordering::Release);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
self.count.fetch_add(1, Ordering::Relaxed) + 1 <= self.limit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user