mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(observability): demote WhatsApp ingest SQLite lock noise (#2917)
This commit is contained in:
@@ -183,6 +183,17 @@ pub enum ExpectedErrorKind {
|
||||
/// reset window elapses and a subsequent init succeeds.
|
||||
///
|
||||
MemoryStoreBreakerOpen,
|
||||
/// WhatsApp structured-ingest write hit a transient SQLite file lock
|
||||
/// (`SQLITE_BUSY` / `SQLITE_LOCKED`) after exhausting the local retry
|
||||
/// budget. This is an expected local-contention condition (typically on
|
||||
/// Windows when another process briefly holds a file lock) and the
|
||||
/// scanner retries on the next tick, so Sentry has no immediate
|
||||
/// remediation path.
|
||||
///
|
||||
/// Anchored narrowly to the whatsapp ingest failure envelope plus the
|
||||
/// SQLite lock text, so unrelated DB lock errors in other domains still
|
||||
/// reach Sentry.
|
||||
WhatsAppDataSqliteBusy,
|
||||
/// Host disk is full — the filesystem returned `ENOSPC` to a write,
|
||||
/// `mkdir`, or `open` syscall. The user cannot recover from this without
|
||||
/// freeing space on their machine, and Sentry has no remediation path
|
||||
@@ -385,6 +396,9 @@ pub fn expected_error_kind(message: &str) -> Option<ExpectedErrorKind> {
|
||||
if is_memory_store_breaker_open(&lower) {
|
||||
return Some(ExpectedErrorKind::MemoryStoreBreakerOpen);
|
||||
}
|
||||
if is_whatsapp_data_sqlite_busy_message(&lower) {
|
||||
return Some(ExpectedErrorKind::WhatsAppDataSqliteBusy);
|
||||
}
|
||||
if is_disk_full_message(&lower) {
|
||||
return Some(ExpectedErrorKind::DiskFull);
|
||||
}
|
||||
@@ -425,6 +439,22 @@ fn is_disk_full_message(lower: &str) -> bool {
|
||||
lower.contains("no space left on device") || lower.contains("not enough space on the disk")
|
||||
}
|
||||
|
||||
/// Match whatsapp structured-ingest failures caused by transient SQLite lock
|
||||
/// contention. Keep this matcher scoped to the whatsapp ingest envelope so we
|
||||
/// don't demote unrelated database failures in other domains.
|
||||
fn is_whatsapp_data_sqlite_busy_message(lower: &str) -> bool {
|
||||
if !lower.contains("[whatsapp_data] ingest failed:") {
|
||||
return false;
|
||||
}
|
||||
if !lower.contains("upsert wa_message") {
|
||||
return false;
|
||||
}
|
||||
lower.contains("database is locked")
|
||||
|| lower.contains("database table is locked")
|
||||
|| lower.contains("database file is locked")
|
||||
|| lower.contains("error code 5")
|
||||
}
|
||||
|
||||
fn is_embedding_backend_auth_failure(lower: &str) -> bool {
|
||||
lower.contains("embedding api error")
|
||||
&& lower.contains("401")
|
||||
@@ -1453,6 +1483,14 @@ fn report_expected_message(kind: ExpectedErrorKind, message: &str, domain: &str,
|
||||
"[observability] {domain}.{operation} skipped expected memory-store circuit-breaker-open error"
|
||||
);
|
||||
}
|
||||
ExpectedErrorKind::WhatsAppDataSqliteBusy => {
|
||||
tracing::warn!(
|
||||
domain = domain,
|
||||
operation = operation,
|
||||
kind = "whatsapp_data_sqlite_busy",
|
||||
"[observability] {domain}.{operation} skipped expected whatsapp_data sqlite busy/locked error"
|
||||
);
|
||||
}
|
||||
ExpectedErrorKind::FilesystemUserPathInvalid => {
|
||||
// User-input validation failure surfaced at the RPC
|
||||
// boundary — e.g. `openhuman.vault_create` called with a
|
||||
@@ -2489,6 +2527,35 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_whatsapp_data_sqlite_busy_errors() {
|
||||
for raw in [
|
||||
r#"[whatsapp_data] ingest failed: upsert wa_message chat=120363402402350155@g.us msg=false_120363402402350155@g.us_3A357F28AE74548B1507_207897942335683@lid: database is locked: Error code 5: The database file is locked"#,
|
||||
r#"rpc.invoke_method failed: [whatsapp_data] ingest failed: upsert wa_message [email] msg=false_120363402402350155@g.us_3A357F28AE74548B1507_207897942335683@lid: database is locked: Error code 5: The database file is locked"#,
|
||||
] {
|
||||
assert_eq!(
|
||||
expected_error_kind(raw),
|
||||
Some(ExpectedErrorKind::WhatsAppDataSqliteBusy),
|
||||
"should classify whatsapp_data sqlite busy/locked: {raw}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_classify_unrelated_sqlite_lock_messages_as_whatsapp_busy() {
|
||||
for raw in [
|
||||
"failed to run subconscious schema DDL: database is locked",
|
||||
"memory queue write failed: database table is locked",
|
||||
"[whatsapp_data] list_messages failed: database is locked",
|
||||
] {
|
||||
assert_ne!(
|
||||
expected_error_kind(raw),
|
||||
Some(ExpectedErrorKind::WhatsAppDataSqliteBusy),
|
||||
"must not classify as whatsapp_data sqlite busy: {raw}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_classify_unrelated_messages_as_memory_pii_rejection() {
|
||||
// A generic "personal identifiers" mention without the "cannot contain"
|
||||
|
||||
Reference in New Issue
Block a user