APScheduler BackgroundScheduler with an in-memory jobstore: working versions (tested 2026-10-16)
Register interval and one-off jobs on a BackgroundScheduler backed by MemoryJobStore, then test scheduling, replacement and execution offline without a persistent store.
passed6 passed · 0 failed2026-10-16 00:01 UTC- Status
- passed
- Last passed
- 2026-10-16 00:01 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions2
apscheduler@3.11.3pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
test environment
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38826982604
The code
Exactly the files that passed. Your agent can pull them with get_recipe("apscheduler-memory-jobstore") (install), or see them on GitHub.
requirements.txt
apscheduler==3.11.3 pytest==9.1.1
scheduler.py
from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.schedulers.background import BackgroundScheduler
def build_scheduler(paused: bool = False) -> BackgroundScheduler:
# MemoryJobStore holds jobs in this process only; nothing survives a restart.
scheduler = BackgroundScheduler(
jobstores={"default": MemoryJobStore()},
executors={"default": ThreadPoolExecutor(2)},
job_defaults={"coalesce": True, "max_instances": 1, "misfire_grace_time": 5},
)
scheduler.start(paused=paused)
return scheduler
def schedule_interval(scheduler, func, seconds, job_id):
return scheduler.add_job(func, "interval", seconds=seconds, id=job_id)
def schedule_once(scheduler, func, run_at, job_id):
return scheduler.add_job(func, "date", run_date=run_at, id=job_id)
tests/test_scheduler.py
import threading
import time
from datetime import datetime, timedelta, timezone
import pytest
from apscheduler.jobstores.base import ConflictingIdError
from apscheduler.jobstores.memory import MemoryJobStore
from scheduler import build_scheduler, schedule_interval, schedule_once
def test_default_jobstore_is_memory():
s = build_scheduler()
assert isinstance(s._jobstores["default"], MemoryJobStore)
s.shutdown(wait=False)
def test_jobs_live_only_in_memory():
s = build_scheduler()
schedule_interval(s, lambda: None, 60, "tick")
assert s.get_job("tick") is not None
s.shutdown(wait=False)
fresh = build_scheduler()
assert fresh.get_job("tick") is None
fresh.shutdown(wait=False)
def test_duplicate_id_conflicts_unless_replaced():
s = build_scheduler()
schedule_interval(s, lambda: None, 60, "tick")
with pytest.raises(ConflictingIdError):
schedule_interval(s, lambda: None, 30, "tick")
job = s.add_job(lambda: None, "interval", seconds=30, id="tick", replace_existing=True)
assert job.trigger.interval.total_seconds() == 30
s.shutdown(wait=False)
def test_interval_next_run_time_is_future():
s = build_scheduler()
before = datetime.now(timezone.utc)
job = schedule_interval(s, lambda: None, 5, "tick")
assert job.next_run_time > before
s.shutdown(wait=False)
def test_paused_scheduler_defers_until_resumed():
ran = threading.Event()
s = build_scheduler(paused=True)
schedule_interval(s, ran.set, 0.05, "tick")
assert not ran.wait(0.2)
s.resume()
assert ran.wait(2)
s.shutdown(wait=False)
def test_date_job_runs_once_then_disappears():
ran = threading.Event()
s = build_scheduler()
schedule_once(s, ran.set, datetime.now(timezone.utc) - timedelta(seconds=1), "once")
assert ran.wait(2)
for _ in range(50):
if s.get_job("once") is None:
break
time.sleep(0.02)
assert s.get_job("once") is None
s.shutdown(wait=False)
pytest.ini
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.