Skip to content

Add supervised background-task helpers to FleetConnector#83

Merged
leandropineda merged 6 commits into
mainfrom
feat/supervised-background-tasks
Jun 10, 2026
Merged

Add supervised background-task helpers to FleetConnector#83
leandropineda merged 6 commits into
mainfrom
feat/supervised-background-tasks

Conversation

@leandropineda

@leandropineda leandropineda commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

Periodic work placed in _execution_loop is already supervised by the framework: __run_loop wraps each call in try/except, logs the traceback, and retries on the next tick. Work a connector schedules itself with a bare asyncio.create_task is not supervised — if it raises, the exception is stored on a task nobody awaits (never logged), the task is never restarted, and whatever it fed (pose, key-values, etc.) freezes until the process restarts, while independent datasources keep working (which masks the failure).

This adds first-class, reusable helpers so connectors that need off-cadence loops (e.g. a fast pose loop + a slower key-value loop) get supervision instead of hand-rolling fire-and-forget tasks.

Changes

  • FleetConnector._create_supervised_task(name, coro_factory, restart_delay=5.0) — runs a long-lived loop that is logged-with-traceback and restarted if it ever exits/crashes. asyncio.CancelledError propagates for clean shutdown.
  • FleetConnector._spawn_logged_task(name, coro) — one-shot tasks whose failure is logged (with traceback) via a done-callback instead of dying silently; not restarted. Same name-first signature as _create_supervised_task for consistency.
  • __log_task_exception done-callback (used by both) surfaces a task's exception, tagged with the task name.
  • Background tasks are tracked and cancelled + awaited in __disconnect.
  • Require inorbit-edge>=3.1.0 (pyproject.toml) so connectors built on this framework transitively get the edge-sdk MQTT callback-resilience fix.
  • examples/simple-connector now demonstrates both helpers: a supervised _speed_poll_loop (faster cadence than _execution_loop) and a one-shot _announce_firmware scheduled via _spawn_logged_task.
  • TODOs in __supervise for follow-ups: a background_task_errors metric and capped exponential backoff on repeated crashes.

New (additive) framework API; the only dependency change is the inorbit-edge lower-bound bump.

Test plan

  • 3 tests in tests/test_connector.py::TestSupervisedBackgroundTasks (restart-on-crash, cancellation-on-__disconnect, one-shot failure logged + named).
  • Manually exercised against examples/simple-connector (session pool mocked, faults injected): supervised loop crashes → logs → restarts → recovers; one-shot fails → logs once → not restarted.
  • Full suite: 231 passed. flake8 clean, black --check clean.

🤖 Generated with Claude Code

leandropineda and others added 5 commits June 9, 2026 13:24
Periodic work placed in `_execution_loop` is already supervised by the
framework: `__run_loop` wraps it in try/except, logs the traceback, and
retries on the next tick. Work scheduled with a bare `asyncio.create_task`
is not: if it raises, the exception is stored on a task nobody awaits (so it
is never logged), the task is never restarted, and whatever it fed (e.g.
pose / key-values) freezes until the process restarts -- while independent
datasources keep working, which masks the failure.

Add to FleetConnector:
- `_create_supervised_task(name, coro_factory, restart_delay)`: runs a
  long-lived loop that is logged-with-traceback and restarted if it ever
  exits or crashes (CancelledError propagates for clean shutdown).
- `_spawn_logged_task(coro)`: one-shot tasks whose failures are surfaced via
  a done-callback instead of dying silently.
- Track these tasks and cancel/await them in `__disconnect`.

Tests: 3 new cases in tests/test_connector.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
edge-sdk 3.1.0 stops a callback exception from killing the paho network
loop thread (guarded callbacks + suppress_exceptions) and surfaces it via
enable_logger. Connectors built on this framework get that fix transitively.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ckoff

- examples/simple-connector: move odometry polling into a supervised
  _speed_poll_loop scheduled via _create_supervised_task, showing a loop on a
  faster cadence than _execution_loop that logs+restarts instead of dying.
- __supervise: TODO(metrics) to emit a background_task_errors counter, and
  TODO(backoff) for capped exponential backoff on repeated crashes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- examples/simple-connector: add a one-shot _announce_firmware startup task
  scheduled via _spawn_logged_task, alongside the supervised speed loop, to
  show the fire-and-forget-but-logged (not restarted) pattern.
- _spawn_logged_task now passes name through to the task so __log_task_exception
  identifies which task failed (the name arg was previously unused).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both now lead with a required `name`: _spawn_logged_task(name, coro) to match
_create_supervised_task(name, coro_factory, ...). Updates the example and test
call sites.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@leandropineda
leandropineda requested a review from b-Tomas June 9, 2026 20:51

@b-Tomas b-Tomas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat feature

Could you update the documentation as well?

@leandropineda

leandropineda commented Jun 10, 2026 via email

Copy link
Copy Markdown
Member Author

@leandropineda
leandropineda merged commit 691a1ea into main Jun 10, 2026
13 checks passed
@leandropineda
leandropineda deleted the feat/supervised-background-tasks branch June 10, 2026 09:54
Sign up for free to 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.

2 participants