Skip to content

Commit 69d9b9b

Browse files
committed
add query timeout as separate variable
1 parent 5b78667 commit 69d9b9b

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

packages/sqlite-web-core/src/coordination.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub enum LeadershipRole {
3030
pub struct WorkerConfig {
3131
pub db_name: String,
3232
pub follower_timeout_ms: f64,
33+
pub query_timeout_ms: f64,
3334
}
3435

3536
pub fn worker_config_from_global() -> Result<WorkerConfig, JsValue> {
@@ -60,9 +61,22 @@ pub fn worker_config_from_global() -> Result<WorkerConfig, JsValue> {
6061
5000.0
6162
}
6263

64+
fn get_query_timeout_from_global() -> f64 {
65+
let global = js_sys::global();
66+
let val = Reflect::get(&global, &JsValue::from_str("__SQLITE_QUERY_TIMEOUT_MS"))
67+
.unwrap_or(JsValue::UNDEFINED);
68+
if let Some(n) = val.as_f64() {
69+
if n.is_finite() && n >= 0.0 {
70+
return n;
71+
}
72+
}
73+
30000.0
74+
}
75+
6376
Ok(WorkerConfig {
6477
db_name: get_db_name_from_global()?,
6578
follower_timeout_ms: get_follower_timeout_from_global(),
79+
query_timeout_ms: get_query_timeout_from_global(),
6680
})
6781
}
6882

@@ -113,6 +127,7 @@ pub struct CoordinatorState {
113127
pub leader_ready: Rc<RefCell<bool>>,
114128
pub ready_signaled: Rc<RefCell<bool>>,
115129
pub follower_timeout_ms: f64,
130+
pub query_timeout_ms: f64,
116131
pub channel: BroadcastChannel,
117132
pub db_worker_ready: Rc<RefCell<bool>>,
118133
pub db_worker: Rc<RefCell<Option<Worker>>>,
@@ -144,6 +159,7 @@ impl CoordinatorState {
144159
leader_ready: Rc::new(RefCell::new(false)),
145160
ready_signaled: Rc::new(RefCell::new(false)),
146161
follower_timeout_ms: config.follower_timeout_ms,
162+
query_timeout_ms: config.query_timeout_ms,
147163
channel: create_broadcast_channel(&config.db_name)?,
148164
db_worker_ready: Rc::new(RefCell::new(false)),
149165
db_worker: Rc::new(RefCell::new(None)),
@@ -296,9 +312,10 @@ impl CoordinatorState {
296312
.as_string()
297313
.ok_or_else(|| JsValue::from_str("Embedded worker source is missing"))?;
298314
let preamble = format!(
299-
"self.__SQLITE_DB_ONLY = true;\nself.__SQLITE_DB_NAME = {};\nself.__SQLITE_FOLLOWER_TIMEOUT_MS = {};\n",
315+
"self.__SQLITE_DB_ONLY = true;\nself.__SQLITE_DB_NAME = {};\nself.__SQLITE_FOLLOWER_TIMEOUT_MS = {};\nself.__SQLITE_QUERY_TIMEOUT_MS = {};\n",
300316
db_name_encoded,
301317
self.follower_timeout_ms,
318+
self.query_timeout_ms,
302319
);
303320

304321
let parts = js_sys::Array::new();
@@ -403,7 +420,7 @@ impl CoordinatorState {
403420
.borrow_mut()
404421
.insert(query_id.clone(), request_id);
405422
let pending = Rc::clone(&self.follower_pending);
406-
let timeout = self.follower_timeout_ms;
423+
let timeout = self.query_timeout_ms;
407424
let timeout_query_id = query_id.clone();
408425
spawn_local(async move {
409426
sleep_ms(timeout.ceil() as i32).await;
@@ -943,10 +960,34 @@ mod tests {
943960
);
944961
}
945962

963+
#[wasm_bindgen_test]
964+
fn worker_config_reads_custom_timeouts() {
965+
set_global_str("__SQLITE_DB_NAME", "testdb-timeouts");
966+
set_global_num("__SQLITE_FOLLOWER_TIMEOUT_MS", 1234.0);
967+
set_global_num("__SQLITE_QUERY_TIMEOUT_MS", 4321.0);
968+
969+
let cfg = worker_config_from_global().expect("config");
970+
assert_eq!(cfg.follower_timeout_ms, 1234.0);
971+
assert_eq!(cfg.query_timeout_ms, 4321.0);
972+
}
973+
974+
#[wasm_bindgen_test]
975+
fn worker_config_defaults_query_timeout() {
976+
set_global_str("__SQLITE_DB_NAME", "testdb-timeouts-default");
977+
let _ = Reflect::delete_property(
978+
&js_sys::global(),
979+
&JsValue::from_str("__SQLITE_QUERY_TIMEOUT_MS"),
980+
);
981+
982+
let cfg = worker_config_from_global().expect("config");
983+
assert_eq!(cfg.query_timeout_ms, 30000.0);
984+
}
985+
946986
#[wasm_bindgen_test(async)]
947987
async fn coordinator_broadcasts_leader_and_ready() {
948988
set_global_str("__SQLITE_DB_NAME", "testdb-coordinator");
949989
set_global_num("__SQLITE_FOLLOWER_TIMEOUT_MS", 100.0);
990+
set_global_num("__SQLITE_QUERY_TIMEOUT_MS", 100.0);
950991
set_global_str(
951992
"__SQLITE_EMBEDDED_WORKER",
952993
"self.postMessage({type:'worker-ready'}); self.onmessage = ev => { const d = ev.data || {}; if (d.type === 'execute-query') { self.postMessage({type:'query-result', requestId:d.requestId, result:'{\"ok\":true}', error:null}); } };",
@@ -988,6 +1029,7 @@ mod tests {
9881029
async fn leader_ping_responds_based_on_db_readiness() {
9891030
set_global_str("__SQLITE_DB_NAME", "testdb-ping");
9901031
set_global_num("__SQLITE_FOLLOWER_TIMEOUT_MS", 50.0);
1032+
set_global_num("__SQLITE_QUERY_TIMEOUT_MS", 50.0);
9911033
set_global_str("__SQLITE_EMBEDDED_WORKER", "");
9921034

9931035
let cfg = worker_config_from_global().expect("config");
@@ -1039,6 +1081,7 @@ mod tests {
10391081
async fn lock_request_failure_keeps_follower_role() {
10401082
set_global_str("__SQLITE_DB_NAME", "testdb-lock-failure");
10411083
set_global_num("__SQLITE_FOLLOWER_TIMEOUT_MS", 50.0);
1084+
set_global_num("__SQLITE_QUERY_TIMEOUT_MS", 50.0);
10421085
set_global_str("__SQLITE_EMBEDDED_WORKER", "");
10431086

10441087
// Stub navigator.locks.request to throw so acquisition fails.
@@ -1081,6 +1124,7 @@ mod tests {
10811124
async fn db_worker_failure_resets_and_reports() {
10821125
set_global_str("__SQLITE_DB_NAME", "testdb-db-failure");
10831126
set_global_num("__SQLITE_FOLLOWER_TIMEOUT_MS", 50.0);
1127+
set_global_num("__SQLITE_QUERY_TIMEOUT_MS", 50.0);
10841128
set_global_str("__SQLITE_EMBEDDED_WORKER", "");
10851129

10861130
let cfg = worker_config_from_global().expect("config");
@@ -1176,6 +1220,7 @@ mod tests {
11761220
WorkerConfig {
11771221
db_name: "testdb-fake".to_string(),
11781222
follower_timeout_ms: 10.0,
1223+
query_timeout_ms: 10.0,
11791224
},
11801225
hooks,
11811226
);

packages/sqlite-web/src/tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ fn test_worker_template_generation() {
133133
worker_code.contains("__SQLITE_FOLLOWER_TIMEOUT_MS"),
134134
"Worker template should embed follower timeout configuration"
135135
);
136+
assert!(
137+
worker_code.contains("__SQLITE_QUERY_TIMEOUT_MS"),
138+
"Worker template should embed query timeout configuration"
139+
);
136140
}
137141

138142
#[wasm_bindgen_test(async)]

packages/sqlite-web/src/worker_template.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub fn generate_self_contained_worker(db_name: &str) -> String {
77
let embedded_body = serde_json::to_string(include_str!("embedded_worker.js"))
88
.unwrap_or_else(|_| "\"\"".to_string());
99
let prefix = format!(
10-
"self.__SQLITE_DB_NAME = {};\nself.__SQLITE_FOLLOWER_TIMEOUT_MS = 5000.0;\nself.__SQLITE_EMBEDDED_WORKER = {};\n",
10+
"self.__SQLITE_DB_NAME = {};\nself.__SQLITE_FOLLOWER_TIMEOUT_MS = 5000.0;\nself.__SQLITE_QUERY_TIMEOUT_MS = 30000.0;\nself.__SQLITE_EMBEDDED_WORKER = {};\n",
1111
encoded, embedded_body
1212
);
1313
// Use the bundled worker template with embedded WASM
@@ -33,6 +33,10 @@ mod tests {
3333
output.contains("self.__SQLITE_FOLLOWER_TIMEOUT_MS = 5000.0;"),
3434
"timeout constant should be injected"
3535
);
36+
assert!(
37+
output.contains("self.__SQLITE_QUERY_TIMEOUT_MS = 30000.0;"),
38+
"query timeout constant should be injected"
39+
);
3640
assert!(
3741
output.contains("self.__SQLITE_EMBEDDED_WORKER = "),
3842
"embedded worker body should be stored on the global"

svelte-test/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)