Quick Start
1
Agent with background runner
2
Recipe in the background
3
Async callers (FastAPI / Jupyter)
Inside a running event loop (a FastAPI handler, a Jupyter cell, or any
async def), use arun_background — the sync run_background raises RuntimeError there instead of deadlocking:Features
- Async Execution: Run tasks without blocking
- Concurrency Control: Limit concurrent tasks
- Progress Tracking: Monitor task status
- Timeout Support: Set execution time limits
- Cancellation: Cancel running tasks
Configuration
Task Status
In-session /tasks command
Inspect and cancel background tasks from inside a praisonai code session or a bot chat — no need to Ctrl-C and run praisonai background list.
Type
/tasks after kicking off a background=True run to check on it without leaving the conversation:
In bot chats,
/tasks is per-user: a caller can only see and cancel tasks whose metadata["user_id"] matches their bot user id. Tasks submitted from the CLI or REPL without a user_id are not exposed to bot users — fail-closed by design.Common Pattern: check on a background run from anywhere
1
Kick off a background task in praisonai code
Ask the agent for a long research task with
background=True. The agent replies with a task id and keeps chatting.2
Peek a few minutes later
Type
/tasks — the research shows as running at 60%. Type /tasks <id> for the current progress detail.3
Switch to your Telegram bot
Type
/tasks there. Because bot /tasks is per-user scoped, you see only the tasks you submitted from Telegram — the REPL ones stay hidden.4
Cancel when no longer needed
/tasks cancel <id> — the task actually stops (its underlying future is cancelled, not just the record marked).Shared runner accessor
Every inspection surface resolves the same process-wide runner throughget_background_runner().
/tasks sees the same tasks regardless of which surface submitted them. BackgroundRunner is still available directly for advanced users who need a private runner.
CLI Usage
Safe Defaults
Low-level API Reference
BackgroundRunner Direct Usage
Submitting Tasks
Task Management
Synchronous Job Manager
For simpler use cases, useBackgroundJobManager for synchronous job management:
Durability — survive a restart
An in-memory-only runner drops every in-flight job on a restart, including the promised deliver-back — pass astore= to persist jobs and recover them on boot.
Durability is opt-in: omit store= and behaviour is byte-for-byte as before (pure in-memory, zero overhead); supply a store and every state transition is persisted.
1
Enable persistence (opt-in)
2
Reconcile once at startup
Call
reconcile_on_start() once at boot, after wiring the deliver-back handler:New API surface
reconcile_on_start(redeliver) passes the persisted JobInfo to your redeliver callback — make it idempotent, since a raised exception means “retry on the next restart” (the job is left undelivered, never lost).
LOST jobs are age-evictable by cleanup_completed(max_age=...), so reconciled orphans don’t leak across restarts.Architecture
The sync wrappers andScheduleLoop bridge the gap between disconnected modules:
submit_sync()/submit_agent_sync()— let sync code submit background tasks without asyncio boilerplateScheduleLoop— polls for due jobs on a daemon thread and fires your callback
Sync Wrappers
For sync code (scripts, bot handlers,Agent.start() callbacks), use the sync-friendly methods that handle asyncio automatically:
submit_sync()
Submit any callable from synchronous code. A daemon event loop thread is created lazily on first call.submit_agent_sync()
Submit an Agent task from synchronous code. Resolves the agent’s callable (start → chat → run) automatically.
cancel_task_sync()
Cancel a task from sync code or an unrelated event loop. It hops threads viarun_coroutine_threadsafe, so it’s safe to call from within a running event loop and actually stops the underlying future.
Terminal-branch guarantee (PR #3883):
on_complete(task) fires on every terminal branch — success, generic exception, asyncio.TimeoutError, and asyncio.CancelledError. Before #3883 it did not fire on timeout or cancel, so callers writing subscribers had to poll .status to detect those. That workaround is no longer needed. Inspect task.status, task.error, and task.result inside your callback to distinguish outcomes.asyncio.CancelledError for cooperative shutdown — but only after on_complete fires.
ScheduleLoop
ScheduleLoop bridges scheduled jobs to actual execution. It runs a daemon thread that polls get_due_jobs() and fires your callback. To skip ticks cheaply before the model turn runs, see pre_run in Schedule Tools.
Combined Example: Scheduler + Background
ScheduleLoop is the default SchedulerProviderProtocol — the in-process poll thread, also exported as InProcessScheduleProvider. For event-driven / serverless firing (webhook, systemd timer, cron, K8s CronJob), see Scheduler Providers.Error handling: If
on_trigger() raises an exception, it’s logged but not propagated — the loop continues with remaining jobs and future ticks.Zero Performance Impact
The background module uses lazy loading — no overhead when not used:Best Practices
Cap concurrent tasks
Cap concurrent tasks
Set
BackgroundConfig(max_concurrent_tasks=...) to match CPU and API rate limits — unbounded parallelism can exhaust tokens or file handles.Always await task.wait with a timeout
Always await task.wait with a timeout
Background work can hang on tool calls; pass
timeout= so your main loop can cancel or retry instead of blocking forever.Pair with ScheduleLoop for cron-style work
Pair with ScheduleLoop for cron-style work
Fire scheduled jobs into
BackgroundRunner.submit_agent_sync so reminders run without blocking the scheduler thread.Use async-jobs for HTTP clients
Use async-jobs for HTTP clients
When callers are external services, prefer the Async Jobs server instead of embedding
BackgroundRunner in app code.Related
Async Jobs
HTTP API for submitting and polling long-running agent jobs.
Schedule Tools
Let agents create reminders that trigger background runs.
Bot /tasks Command
Inspect and cancel background tasks from Telegram, Slack, Discord — per-user scoped.

