fixed sqlite lock
This commit is contained in:
+36
-2
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user