wire reminder ops into the in-agent socket dispatch (#2635 inc 1)
This commit is contained in:
parent
174e277340
commit
ecd9030305
6 changed files with 178 additions and 45 deletions
|
|
@ -216,6 +216,11 @@ fn graceful_stop_message() -> hive_sh4re::DeliveredMessage {
|
|||
/// enum so `serve_loop` can pattern-match without seeing it directly.
|
||||
enum RecvOutcome {
|
||||
/// Long-poll returned at least one message; first one is detached.
|
||||
/// Also reused for a fired reminder: `reminder_timer` pushes a *real*
|
||||
/// `DeliveredMessage` (unlike `LocalTodo`'s synthetic hint) since the
|
||||
/// body/id is per-row data the producer already resolved, so the
|
||||
/// select arm wraps it straight into this variant — no dedicated
|
||||
/// `LocalReminder` variant needed.
|
||||
Message(hive_sh4re::DeliveredMessage),
|
||||
/// Long-poll timed out cleanly (empty `Messages` response). Caller
|
||||
/// sleeps then retries.
|
||||
|
|
@ -234,11 +239,6 @@ enum RecvOutcome {
|
|||
LocalTodo,
|
||||
}
|
||||
|
||||
/// Reminder fires are pushed as a *real* `DeliveredMessage` (unlike
|
||||
/// `LocalTodo`'s synthetic hint) since the body/id is per-row data the
|
||||
/// producer (`reminder_timer`) already resolved — so the select arm
|
||||
/// wraps it straight into `RecvOutcome::Message`, no dedicated variant.
|
||||
|
||||
/// Wire surface abstraction. `AgentSurface` is the only impl — the trait
|
||||
/// exists to keep the turn loop generic and testable. Every function that
|
||||
/// talks to the broker goes through this so there are zero hard-coded
|
||||
|
|
@ -460,33 +460,15 @@ async fn serve_main<S: Surface>(socket: &Path, poll_ms: u64) -> Result<()> {
|
|||
tracing::error!(error = %e, "web_ui::serve exited with error");
|
||||
}
|
||||
});
|
||||
// In-agent todo socket (loose-ends v2): the harness owns the todo store
|
||||
// locally and serves the in-container producers on `HIVE_AGENT_SOCKET`.
|
||||
// A new/changed upsert fires `todo_wake` so the serve loop drives a turn
|
||||
// directly — no broker round-trip, no marker files. Best-effort: if the
|
||||
// store can't open, the socket just isn't served.
|
||||
let todo_wake = Arc::new(tokio::sync::Notify::new());
|
||||
match todos::Todos::open(&paths::todos_db()) {
|
||||
Ok(store) => {
|
||||
let store = Arc::new(store);
|
||||
let wake = todo_wake.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = todo_server::run(store, wake).await {
|
||||
tracing::error!(error = %e, "in-agent todo socket exited with error");
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(error = ?e, "open todos db failed — in-agent todo socket disabled");
|
||||
}
|
||||
}
|
||||
// Harness-local reminders (#2635 increment 1): a due reminder fires
|
||||
// straight into an mpsc channel the serve loop races against the
|
||||
// broker long-poll (unlike todos, a fire carries real per-row data,
|
||||
// so a bare `Notify` doesn't fit — see `reminder_timer` docs).
|
||||
// Best-effort like the todo store above: `reminder_timer::run` parks
|
||||
// forever (never sends) instead of exiting when the store can't
|
||||
// open, so the channel never observes a "closed" state.
|
||||
// Best-effort: `reminder_timer::run` parks forever (never sends)
|
||||
// instead of exiting when the store can't open, so the channel
|
||||
// never observes a "closed" state. Opened before the todo socket
|
||||
// below so the same `Arc` can be handed to its request dispatch
|
||||
// (reminder ops share the todo socket/listener).
|
||||
let (reminder_tx, reminder_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
let reminder_store = match reminders::Reminders::open(&paths::reminders_db()) {
|
||||
Ok(store) => Some(Arc::new(store)),
|
||||
|
|
@ -495,7 +477,32 @@ async fn serve_main<S: Surface>(socket: &Path, poll_ms: u64) -> Result<()> {
|
|||
None
|
||||
}
|
||||
};
|
||||
tokio::spawn(reminder_timer::run(reminder_store, reminder_tx));
|
||||
tokio::spawn(reminder_timer::run(reminder_store.clone(), reminder_tx));
|
||||
// In-agent todo socket (loose-ends v2 + #2635 reminders): the harness
|
||||
// owns the todo + reminder stores locally and serves the
|
||||
// in-container producers on `HIVE_AGENT_SOCKET`. A new/changed todo
|
||||
// upsert fires `todo_wake` so the serve loop drives a turn directly —
|
||||
// no broker round-trip, no marker files. Best-effort: if the todos
|
||||
// store can't open, the whole socket isn't served (reminder ops ride
|
||||
// along on the same listener, so they're gated on the same store —
|
||||
// acceptable since a from-scratch harness boot either has a writable
|
||||
// harness dir or doesn't).
|
||||
let todo_wake = Arc::new(tokio::sync::Notify::new());
|
||||
match todos::Todos::open(&paths::todos_db()) {
|
||||
Ok(store) => {
|
||||
let store = Arc::new(store);
|
||||
let wake = todo_wake.clone();
|
||||
let reminders = reminder_store.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = todo_server::run(store, wake, reminders).await {
|
||||
tracing::error!(error = %e, "in-agent todo socket exited with error");
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(error = ?e, "open todos db failed — in-agent todo socket disabled");
|
||||
}
|
||||
}
|
||||
if matches!(initial, LoginState::NeedsLogin) {
|
||||
login::wait_for_login(&claude_dir, login_state.clone(), &bus, poll_ms).await;
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue