fixed sqlite lock

This commit is contained in:
2026-06-30 02:39:24 -03:00
parent 8416b92a8d
commit fc3b2ef309
+36 -2
View File
@@ -486,6 +486,9 @@ async fn redis_cli(redis_url: &str, args: &[&str]) -> Result<String> {
async fn init_sqlite(sqlite_path: &Path) -> Result<()> { async fn init_sqlite(sqlite_path: &Path) -> Result<()> {
let sql = r#" let sql = r#"
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA busy_timeout = 5000;
CREATE TABLE IF NOT EXISTS rtsp_feed_results ( CREATE TABLE IF NOT EXISTS rtsp_feed_results (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
checked_at INTEGER NOT NULL, checked_at INTEGER NOT NULL,
@@ -520,13 +523,22 @@ async fn insert_sqlite_result(
status = sql_quote(&status), status = sql_quote(&status),
error = sql_nullable_quote(error), error = sql_nullable_quote(error),
); );
sqlite_exec(sqlite_path, &sql).await sqlite_exec_with_retry(sqlite_path, &sql).await
} }
async fn sqlite_exec(sqlite_path: &Path, sql: &str) -> Result<()> { async fn sqlite_exec(sqlite_path: &Path, sql: &str) -> Result<()> {
let output = timeout(Duration::from_secs(20), async { let output = timeout(Duration::from_secs(20), async {
let mut command = Command::new("sqlite3"); let mut command = Command::new("sqlite3");
command.kill_on_drop(true).arg(sqlite_path).arg(sql); command
.kill_on_drop(true)
.arg("-cmd")
.arg("PRAGMA busy_timeout = 5000;")
.arg("-cmd")
.arg("PRAGMA journal_mode = WAL;")
.arg("-cmd")
.arg("PRAGMA synchronous = NORMAL;")
.arg(sqlite_path)
.arg(sql);
command.output().await command.output().await
}) })
.await .await
@@ -547,6 +559,28 @@ async fn sqlite_exec(sqlite_path: &Path, sql: &str) -> Result<()> {
Ok(()) Ok(())
} }
async fn sqlite_exec_with_retry(sqlite_path: &Path, sql: &str) -> Result<()> {
let mut last_err: Option<anyhow::Error> = None;
for attempt in 0..5 {
match sqlite_exec(sqlite_path, sql).await {
Ok(()) => return Ok(()),
Err(err) if is_sqlite_locked(&err) && attempt < 4 => {
last_err = Some(err);
sleep(Duration::from_millis(200 * (attempt + 1) as u64)).await;
}
Err(err) => return Err(err),
}
}
Err(last_err.unwrap_or_else(|| anyhow!("sqlite3 failed after retries")))
}
fn is_sqlite_locked(err: &anyhow::Error) -> bool {
let text = err.to_string().to_ascii_lowercase();
text.contains("database is locked") || text.contains("busy")
}
fn load_ip_list(input: &str) -> Result<Vec<String>> { fn load_ip_list(input: &str) -> Result<Vec<String>> {
let content = match fs::read_to_string(input) { let content = match fs::read_to_string(input) {
Ok(content) => content, Ok(content) => content,