mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-11-15 13:12:22 +01:00
Two users on 2026.7.x reported the app going half-dead: local editing kept
working, but Send did nothing and every encrypted secret rendered blank until
they restarted. The webview console carried a Rust task panic —
Delete task failed: task 1314 panicked with message
"Failed to get new DB connection from the pool: Error(None)"
`Error(None)` is r2d2's acquire timeout. `QueryManager::connect` and `with_tx`
turned that timeout into `expect`, so a pool that was momentarily full took down
whatever task asked for a connection instead of reporting a failure the caller
could show, retry, or ignore. Every DB-backed path shares those two functions,
which is why one stalled pool reads as "Send is dead and the secrets are gone".
Acquisition is now fallible end to end: `connect()` and `BlobManager::connect()`
return `Result`, and so do the `db()`/`blobs()` accessors on every host. Call
sites propagate with `?` where they already returned a result; the fire-and-forget
writers (streaming events, the model-change poller) log and carry on. `with_conn`
had no callers and only added a third panic, so it is gone.
Two places held a pooled connection across work that has nothing to do with the
database and can block for a long time — the OS keyring in
`EncryptionManager::get_workspace_key`, and the sync directory walk in
`cmd_sync_calculate`. Both now hand the connection back first. Those are the
paths behind the two visible symptoms.
Not fixed here: the gRPC streaming block in yaak-app-client still `.unwrap()`s
its database writes, as it did before, so acquisition failures panic there too.
`ProxyQueryManager` in the separate proxy app keeps its own `expect`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
112 lines
3.4 KiB
Rust
112 lines
3.4 KiB
Rust
#![allow(dead_code)]
|
|
|
|
pub mod http_server;
|
|
|
|
use assert_cmd::Command;
|
|
use assert_cmd::cargo::cargo_bin_cmd;
|
|
use std::path::Path;
|
|
use yaak_models::models::{Folder, GrpcRequest, HttpRequest, WebsocketRequest, Workspace};
|
|
use yaak_models::query_manager::QueryManager;
|
|
use yaak_models::util::UpdateSource;
|
|
|
|
pub fn cli_cmd(data_dir: &Path) -> Command {
|
|
let mut cmd = cargo_bin_cmd!("yaak");
|
|
cmd.arg("--data-dir").arg(data_dir);
|
|
cmd
|
|
}
|
|
|
|
pub fn parse_created_id(stdout: &[u8], label: &str) -> String {
|
|
String::from_utf8_lossy(stdout)
|
|
.trim()
|
|
.split_once(": ")
|
|
.map(|(_, id)| id.to_string())
|
|
.unwrap_or_else(|| panic!("Expected id in '{label}' output"))
|
|
}
|
|
|
|
pub fn query_manager(data_dir: &Path) -> QueryManager {
|
|
let db_path = data_dir.join("db.sqlite");
|
|
let blob_path = data_dir.join("blobs.sqlite");
|
|
let (query_manager, _blob_manager, _rx) =
|
|
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize DB");
|
|
query_manager
|
|
}
|
|
|
|
pub fn seed_workspace(data_dir: &Path, workspace_id: &str) {
|
|
let workspace = Workspace {
|
|
id: workspace_id.to_string(),
|
|
name: "Seed Workspace".to_string(),
|
|
description: "Seeded for integration tests".to_string(),
|
|
..Default::default()
|
|
};
|
|
|
|
query_manager(data_dir)
|
|
.connect()
|
|
.unwrap()
|
|
.upsert_workspace(&workspace, &UpdateSource::Sync)
|
|
.expect("Failed to seed workspace");
|
|
}
|
|
|
|
pub fn seed_request(data_dir: &Path, workspace_id: &str, request_id: &str) {
|
|
let request = HttpRequest {
|
|
id: request_id.to_string(),
|
|
workspace_id: workspace_id.to_string(),
|
|
name: "Seeded Request".to_string(),
|
|
method: "GET".to_string(),
|
|
url: "https://example.com".to_string(),
|
|
..Default::default()
|
|
};
|
|
|
|
query_manager(data_dir)
|
|
.connect()
|
|
.unwrap()
|
|
.upsert_http_request(&request, &UpdateSource::Sync)
|
|
.expect("Failed to seed request");
|
|
}
|
|
|
|
pub fn seed_folder(data_dir: &Path, workspace_id: &str, folder_id: &str) {
|
|
let folder = Folder {
|
|
id: folder_id.to_string(),
|
|
workspace_id: workspace_id.to_string(),
|
|
name: "Seed Folder".to_string(),
|
|
..Default::default()
|
|
};
|
|
|
|
query_manager(data_dir)
|
|
.connect()
|
|
.unwrap()
|
|
.upsert_folder(&folder, &UpdateSource::Sync)
|
|
.expect("Failed to seed folder");
|
|
}
|
|
|
|
pub fn seed_grpc_request(data_dir: &Path, workspace_id: &str, request_id: &str) {
|
|
let request = GrpcRequest {
|
|
id: request_id.to_string(),
|
|
workspace_id: workspace_id.to_string(),
|
|
name: "Seeded gRPC Request".to_string(),
|
|
url: "https://example.com".to_string(),
|
|
..Default::default()
|
|
};
|
|
|
|
query_manager(data_dir)
|
|
.connect()
|
|
.unwrap()
|
|
.upsert_grpc_request(&request, &UpdateSource::Sync)
|
|
.expect("Failed to seed gRPC request");
|
|
}
|
|
|
|
pub fn seed_websocket_request(data_dir: &Path, workspace_id: &str, request_id: &str) {
|
|
let request = WebsocketRequest {
|
|
id: request_id.to_string(),
|
|
workspace_id: workspace_id.to_string(),
|
|
name: "Seeded WebSocket Request".to_string(),
|
|
url: "wss://example.com/socket".to_string(),
|
|
..Default::default()
|
|
};
|
|
|
|
query_manager(data_dir)
|
|
.connect()
|
|
.unwrap()
|
|
.upsert_websocket_request(&request, &UpdateSource::Sync)
|
|
.expect("Failed to seed WebSocket request");
|
|
}
|