Skip to content

feat(python): AsyncDaemon with async status() (partial #65) - #78

Merged
zackees merged 1 commit into
mainfrom
feat/issue-65-async-daemon
Apr 17, 2026
Merged

feat(python): AsyncDaemon with async status() (partial #65)#78
zackees merged 1 commit into
mainfrom
feat/issue-65-async-daemon

Conversation

@zackees

@zackeeszackees commented Apr 17, 2026

Copy link
Copy Markdown
Member

Summary

Next incremental step on #65 (native async Python API). Adds `AsyncDaemon` as a counterpart to the sync `Daemon` class, mirroring the `AsyncSerialMonitor` pattern from PR #73.

Changes

  • `AsyncDaemon` is purely additive — the sync `Daemon` class keeps all its methods and behavior.
  • Exposes `async status()` as the first method. Like `reset_device` on `AsyncSerialMonitor`, `status` is stateless HTTP so it ports without needing the cross-await state refactor.

Follow-up (tracked in #65)

  • `async ensure_running()`, `async stop()` are straightforward next steps (same HTTP-only pattern).
  • The WebSocket-backed methods (`AsyncSerialMonitor.read_lines`, `write`, `write_json_rpc`, `aenter`/`aexit`) still need the shared WebSocket state refactored to be `Send + Sync` across `await` points before they can be exposed.

Test plan

  • `cargo check -p fbuild-python` clean
  • `cargo clippy --workspace --all-targets -- -D warnings` clean
  • `cargo fmt --all -- --check` clean

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added async daemon status checking with HTTP connectivity and automatic error handling for connection failures and timeouts.

Next incremental step on #65 (native async API). Adds AsyncDaemon as a
counterpart to the sync Daemon class, mirroring the AsyncSerialMonitor
pattern from PR #73.
- AsyncDaemon is purely additive — the sync Daemon class keeps all
its methods and behavior.
- Exposes async status() as the first method. Like reset_device on
AsyncSerialMonitor, status is stateless HTTP so it ports without
needing the cross-await state refactor.
Future work on #65: async ensure_running(), async stop(), and then the
WebSocket-backed AsyncSerialMonitor methods once the shared state is
Send + Sync across await points.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Apr 17, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9a10399e-fe81-4d60-916c-fbbed9088f4d

📥 Commits

Reviewing files that changed from the base of the PR and between 4f153d0 and 8dbdd03.

📒 Files selected for processing (1)
  • crates/fbuild-python/src/lib.rs

📝 Walkthrough

Walkthrough

A new Python-exposed Rust class AsyncDaemon was introduced with a static async method status that performs HTTP GET requests to a daemon info endpoint with a 10-second timeout, converting HTTP and JSON errors into Python exceptions.

Changes

Cohort / File(s)Summary
Async Daemon Status API
crates/fbuild-python/src/lib.rs
Added AsyncDaemon PyO3 class with status() static async method; performs HTTP GET to daemon API with 10s timeout; handles connection/send errors as PyConnectionError, response read/JSON parsing errors as PyRuntimeError; registered in module initializer.

Sequence Diagram(s)

sequenceDiagram
participant Python as Python Client
participant Async as AsyncDaemon
participant Tokio as Tokio Runtime
participant HTTP as HTTP Client
participant Daemon as Daemon API
Python->>Async: status(py)
activate Async
Async->>Tokio: spawn async task
activate Tokio
Tokio->>HTTP: GET /api/daemon/info
activate HTTP
HTTP->>Daemon: send request
activate Daemon
Daemon-->>HTTP: response
deactivate Daemon
HTTP-->>Tokio: response body
deactivate HTTP
Tokio->>Tokio: parse JSON
Tokio-->>Async: future result
deactivate Tokio
Async->>Async: convert to Python
Async-->>Python: PyResult<Bound<PyAny>>
deactivate Async
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐰 Async daemons hopping fast,
HTTP requests unsurpassed,
Timeouts ticking, responses flow,
Python and Rust together glow!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title 'feat(python): AsyncDaemon with async status() (partial #65)' clearly and concisely summarizes the main change: adding a new AsyncDaemon class with an async status() method. It accurately reflects the primary additions shown in the changeset and follows conventional commit formatting.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-65-async-daemon

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zackees
zackees merged commit f2d1590 into mainApr 17, 2026
76 of 79 checks passed
zackees added a commit that referenced this pull request Apr 18, 2026
Extends the AsyncDaemon scaffold (PR #78) with the method set that
#65 explicitly targets: "Daemon/DaemonConnection:
send_op and any other HTTP call".
Added:
- `send_op_async`: tokio/reqwest counterpart to `send_op` that yields
on I/O instead of blocking a runtime thread.
- `AsyncDaemon.ensure_running` / `AsyncDaemon.stop`: native async
lifecycle calls so callers no longer need `_run_in_thread` for
daemon bring-up/shutdown.
- `AsyncDaemonConnection`: new class mirroring `DaemonConnection`
with async `build`, `deploy`, `monitor`, and their `_result`
counterparts. Shares `parse_outcome` / `outcome_to_pydict` with
the sync class so the structured-result schema stays identical.
- `connect_daemon_async` factory.
Re-exports: `AsyncDaemon`, `AsyncDaemonConnection`,
`connect_daemon_async` from `fbuild`; `AsyncSerialMonitor` from
`fbuild.api`.
Still remaining for #65: `AsyncSerialMonitor.read_lines` / `write` /
`write_json_rpc`. These need the shared WebSocket state refactored to
be `Send + Sync` across `.await` points (noted in the scaffold
comment) and are a follow-up PR.
Tests: 3 new Rust tests spin a minimal in-process HTTP mock and
exercise `send_op_async` against success, failure, and connection-
error paths. Failure outcomes must still carry `message` / `exit_code`
/ `stderr` so async callers retain the structured-result parity with
the sync API.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zackees added a commit that referenced this pull request Apr 18, 2026
Extends the AsyncDaemon scaffold (PR #78) with the method set that
#65 explicitly targets: "Daemon/DaemonConnection:
send_op and any other HTTP call".
Added:
- `send_op_async`: tokio/reqwest counterpart to `send_op` that yields
on I/O instead of blocking a runtime thread.
- `AsyncDaemon.ensure_running` / `AsyncDaemon.stop`: native async
lifecycle calls so callers no longer need `_run_in_thread` for
daemon bring-up/shutdown.
- `AsyncDaemonConnection`: new class mirroring `DaemonConnection`
with async `build`, `deploy`, `monitor`, and their `_result`
counterparts. Shares `parse_outcome` / `outcome_to_pydict` with
the sync class so the structured-result schema stays identical.
- `connect_daemon_async` factory.
Re-exports: `AsyncDaemon`, `AsyncDaemonConnection`,
`connect_daemon_async` from `fbuild`; `AsyncSerialMonitor` from
`fbuild.api`.
Still remaining for #65: `AsyncSerialMonitor.read_lines` / `write` /
`write_json_rpc`. These need the shared WebSocket state refactored to
be `Send + Sync` across `.await` points (noted in the scaffold
comment) and are a follow-up PR.
Tests: 3 new Rust tests spin a minimal in-process HTTP mock and
exercise `send_op_async` against success, failure, and connection-
error paths. Failure outcomes must still carry `message` / `exit_code`
/ `stderr` so async callers retain the structured-result parity with
the sync API.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@zackees