What this prompt does
This prompt casts the model as a senior Python backend engineer and asks it to add a background scheduled task to an existing FastAPI app using APScheduler, returning working code rather than pseudocode. It defines six deliverables: an AsyncIOScheduler wired to FastAPI's lifespan (started on boot, stopped on shutdown), the job running at its cadence in the chosen timezone with overlap protection via max_instances=1, a shared async DB session so the job and routes use one connection pool, an auth-guarded manual trigger endpoint, a /healthz endpoint returning last run time, last status, and next scheduled run, and graceful shutdown that lets an in-flight job finish or times out cleanly. The structure works because it keeps scheduling inside the app with a health endpoint you can actually alert on.
Four variables drive it. [job_name] names the job (default sync_external_orders). [job_cadence] sets the interval, like every 10 minutes. [tz] fixes the timezone, defaulting to UTC. [database] names the store, such as PostgreSQL via async SQLAlchemy, which the shared session targets. The overlap protection in deliverable two is the load-bearing part: without max_instances=1, a slow job stacks up and quietly eats the connection pool, so the prompt insists on it. This approach suits one in-process job where a separate cron box or Celery would be overkill.
When to use it
- Your FastAPI app needs periodic background work and a separate cron box or Celery is overkill.
- You want scheduling inside the app with a health endpoint you can alert on.
- Overlap protection matters so a slow job doesn't stack up and exhaust the pool.
- The job and your routes should share one async DB connection pool.
- You need an auth-guarded endpoint to trigger the job manually on demand.
- Graceful shutdown that lets an in-flight job finish cleanly is required.
Example output
Expect the full module plus the changes to main.py. An AsyncIOScheduler is wired to FastAPI's lifespan, started on boot and stopped on shutdown; the [job_name] job runs at [job_cadence] in [tz] with max_instances=1 overlap protection; a shared async session for [database] keeps the job and routes on one pool; an auth-guarded manual trigger endpoint runs the job on demand; a /healthz endpoint returns last run time, last status, and next scheduled run; and graceful shutdown lets an in-flight job finish or times out cleanly. It is integration-ready code you adapt to your app.
Pro tips
- Set
[job_cadence]to your real interval, and remember overlap protection matters more as the cadence tightens. - Fix
[tz]explicitly; leaving it implicit invites off-by-an-hour bugs around daylight saving. - Name
[database]accurately so the shared async session matches your actual driver and pool setup. - Do not skip the overlap protection — without max_instances=1 a slow job stacks up and quietly eats the pool.
- Use the /healthz endpoint as your alerting source; last status and next run time are what you watch.
- Keep the manual trigger auth-guarded so the on-demand endpoint can't be hit by anyone.