Tasks

future.tasks.Task is the unit you pass into Lifespan — once at startup, once at shutdown, or on a fixed interval (cron_tasks).

from future.tasks import Task, Unit

Task constructor

Argument Role
name Label in logs / scheduler
func Sync or async callable to run
args Positional args for func (tuple)
kwargs Keyword args for func
interval How often (required for cron_tasks)
unit Unit.SECONDS / MINUTES / HOURS / DAYS
start_time First run time (datetime); default is “now” when registered
jitter Optional extra delay 0 … jitter seconds on each next-run calculation

Cron tasks need func, interval, and unit. Startup / shutdown tasks only need name and func (interval is ignored).

Wire into Lifespan

from datetime import datetime, timedelta
from future.application import Future
from future.lifespan import Lifespan
from future.tasks import Task, Unit
from app.tasks.Scrape import scraper
from app.tasks.Cleanup import run as cleanup

startup_tasks = [
    Task("boot_log", func=lambda: print("starting")),
]

shutdown_tasks = [
    Task("flush", func=cleanup),
]

cron_tasks = [
    Task("scrape", interval=1, unit=Unit.HOURS, func=scraper),
    Task("scrape_jitter", interval=1, unit=Unit.HOURS, func=scraper, jitter=60),
    Task(
        "daily_backup",
        interval=1,
        unit=Unit.DAYS,
        start_time=datetime.now().replace(hour=2, minute=0, second=0, microsecond=0) + timedelta(days=1),
        func=cleanup,
    ),
    Task("dns", interval=5, unit=Unit.MINUTES, func=check_dns, args=("example.com",)),
]

lifespan = Lifespan(
    startup_tasks=startup_tasks,
    shutdown_tasks=shutdown_tasks,
    cron_tasks=cron_tasks,
)
app = Future(lifespan=lifespan, config=config)

Startup and shutdown

On ASGI lifespan enter, Future runs each startup_tasks entry in order (async awaited, sync in a thread pool), then starts the scheduler and registers cron_tasks.

On exit, the scheduler stops, then shutdown_tasks run the same way.

async def connect_cache():
    ...

def close_files():
    ...

startup_tasks = [Task("cache", func=connect_cache)]
shutdown_tasks = [Task("files", func=close_files)]

Interval (cron) tasks

Fixed intervals only — not crontab expressions. The scheduler checks about once per second and runs due tasks concurrently (asyncio.create_task). Errors are logged; last_run is not updated on failure so the task retries on the next cycle.

Task("scrape", interval=1, unit=Unit.HOURS, func=scraper)
Task("ping", interval=30, unit=Unit.SECONDS, func=ping, kwargs={"url": "https://example.com"})

Each uvicorn worker runs its own scheduler (no cross-worker lock).

Generate a task stub

future make:task Cleanup

Creates something under app/tasks/ with a run() (or similar) callable — pass it as func=:

from app.tasks.Cleanup import run

cron_tasks = [Task("cleanup", interval=1, unit=Unit.DAYS, func=run)]

Built-in examples

future.tasks also exports small helpers (check_dns, check_http_status, daily_backup, …) useful as samples. Prefer app-specific modules under app/tasks/ for real work.

See Lifespan for the ASGI wrapper that runs these lists.