From 0e69d3bd9b1263dbe7a0c564e67fd4a7656dc1a5 Mon Sep 17 00:00:00 2001 From: jif Date: Mon, 21 Sep 2026 15:17:09 +0000 Subject: [PATCH] Batch message-board subscriber reads into one SQLite result (#47050) ## Why Posting to the local agent message board fetched each subscriber row across SQLite's worker thread while holding a write transaction. ## What changed Use `json_group_array(agent)` to fetch subscribers as a single JSON array, then deserialize it before collecting notification recipients. ## Testing Extend the local board test to verify that posting to a channel with no subscribers succeeds without sending notifications. GitOrigin-RevId: ad294e19c78ee501f1de2084f7c02fa96f53418d --- codex-rs/ext/agent-message-board/src/local.rs | 7 +++++-- .../agent-message-board/tests/local_board.rs | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/codex-rs/ext/agent-message-board/src/local.rs b/codex-rs/ext/agent-message-board/src/local.rs index 30e3fa37b2..3d1c157f49 100644 --- a/codex-rs/ext/agent-message-board/src/local.rs +++ b/codex-rs/ext/agent-message-board/src/local.rs @@ -248,14 +248,17 @@ impl LocalAgentMessageBoard { ) } }; + // Return one JSON array to avoid handing each subscriber row across + // SQLite's worker thread while the write transaction is held. let subscribed = sqlx::query_scalar::<_, String>( - "SELECT agent FROM subscriptions WHERE board=? AND target=?", + "SELECT json_group_array(agent) FROM subscriptions WHERE board=? AND target=?", ) .bind(self.identity.to_string()) .bind(target_key(&target)?) - .fetch_all(&mut *tx) + .fetch_one(&mut *tx) .await .map_err(storage_error)?; + let subscribed: Vec = serde_json::from_str(&subscribed).map_err(storage_error)?; for recipient in subscribed { recipients.insert(ThreadId::from_string(&recipient).map_err(storage_error)?); } diff --git a/codex-rs/ext/agent-message-board/tests/local_board.rs b/codex-rs/ext/agent-message-board/tests/local_board.rs index 1b3feedbd9..d1c6e74eb6 100644 --- a/codex-rs/ext/agent-message-board/tests/local_board.rs +++ b/codex-rs/ext/agent-message-board/tests/local_board.rs @@ -165,6 +165,23 @@ async fn shared_handles_resume_posts_and_preserve_subscription_rules() { ) .await .unwrap(); + // Posting still succeeds when the subscriber lookup returns an empty array. + resumed + .post( + root, + PostRequest { + request_id: "no-subscribers".into(), + destination: PostDestination::Channel("proofs".into()), + text: "saved without notifications".into(), + agents_to_notify: Vec::new(), + }, + ) + .await + .unwrap(); + assert_eq!( + *host.notifications.lock().unwrap(), + vec![(child, metadata.clone())] + ); resumed .set_subscription( root,