The Scheduler's task-management endpoints (GET/POST /tasks, PUT
/tasks/{name}) are guarded by verify_api_key, but execute() built a bare
httpx.Client with no Authorization header: the existence probe 401'd
(misread as 'task absent') and every POST/PUT registration failed, so
--execute was never runnable end-to-end against the real Scheduler.
--execute now requires SCHEDULER_API_KEY from the environment (never
stored) and sends Authorization: Bearer on all registrar HTTP calls.
Deploy notes updated alongside the LIBRARY_API_KEY requirement.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbFZyDvYksazX6nYQYZ67L
5.4 KiB
Scheduler Task Definitions (Phase C deploy checklist)
Production task payloads for the homelab's database-driven Scheduler service. These are definitions only — nothing in this repo registers them automatically. Register them as part of the deploy checklist, either via the Scheduler UI/API or with the helper script:
# Preview exactly what would be sent (default):
SCHEDULER_URL=http://<scheduler-host>:8090 \
.venv/bin/python scripts/register_scheduler_tasks.py
# Actually register/update the tasks (deploy checklist step):
SCHEDULER_URL=http://<scheduler-host>:8090 \
SCHEDULER_API_KEY=<scheduler-api-key> \
.venv/bin/python scripts/register_scheduler_tasks.py --execute
Conventions:
-
The Scheduler's task-management endpoints (
GET/POST /tasks,PUT /tasks/{name}) requireAuthorization: Bearer $SCHEDULER_API_KEY. The registrar readsSCHEDULER_API_KEYfrom the environment for its own HTTP calls (--executerefuses to run without it); the key is never stored. This is separate fromLIBRARY_API_KEYbelow, which the Scheduler container needs at task execution time. -
All tasks call the production library-desk container (
http://library-desk:8089) with the explicit production tenantuser=jpmschweitzer(there is no default tenant — Phase B). -
${LIBRARY_API_KEY}is a literal placeholder stored in the task'sauth.tokenfield. The Scheduler'srest_api_executorsubstitutes${ENV_VAR}placeholders from its own environment at execution time (it substitutesurl/payload/auth— NOT plainheaders), so the raw key is never stored in thescheduled_tasks.configJSONB column. The Scheduler container must haveLIBRARY_API_KEYin its environment. Never commit or register the real value. -
The JSON body goes in
config.payload(the executor ignores abodykey). -
Schedule fields use the Scheduler's convention:
-1= every,day_of_week:0= Monday …6= Sunday.
1. Nightly integrity check — 04:30 daily
Read-only report: pages without vectors, orphaned vectors, unexpected Qdrant collections, Document nodes without wiki pages. Caches its result in Redis for the weekly quality report.
{
"task_name": "library_integrity_check",
"service": "library-desk",
"executor": "rest_api_executor",
"priority": 60,
"description": "Nightly read-only integrity check for the library (vectors/graph/wiki/collections)",
"enabled": true,
"max_retries": 2,
"timeout_seconds": 900,
"minute": 30,
"hour": 4,
"day_of_month": -1,
"month": -1,
"day_of_week": -1,
"config": {
"method": "POST",
"url": "http://library-desk:8089/maintenance/integrity-check",
"headers": {
"Content-Type": "application/json"
},
"payload": {
"user": "jpmschweitzer"
},
"auth": {
"type": "bearer",
"token": "${LIBRARY_API_KEY}"
}
}
}
2. Weekly quality report — Sunday 03:00
Runs the duplicate scan, flags stale/metadata-poor pages, folds in the
latest integrity results, and writes the dated report page to
users/jpmschweitzer/system/quality-reports/YYYY-MM-DD.
{
"task_name": "library_quality_report",
"service": "library-desk",
"executor": "rest_api_executor",
"priority": 60,
"description": "Weekly library quality report (dedup, stale pages, missing metadata, integrity) written to the wiki",
"enabled": true,
"max_retries": 2,
"timeout_seconds": 1800,
"minute": 0,
"hour": 3,
"day_of_month": -1,
"month": -1,
"day_of_week": 6,
"config": {
"method": "POST",
"url": "http://library-desk:8089/maintenance/quality-report",
"headers": {
"Content-Type": "application/json"
},
"payload": {
"user": "jpmschweitzer",
"stale_days": 30,
"dedup_threshold": 0.9,
"write_page": true
},
"auth": {
"type": "bearer",
"token": "${LIBRARY_API_KEY}"
}
}
}
3. Daily Paperless orphan cleanup — 05:00
Hits the existing cleanup endpoint (query parameters, empty payload).
dry_run=false deletes vectors/graph nodes for documents that were
removed from Paperless-ngx.
{
"task_name": "library_paperless_orphan_cleanup",
"service": "library-desk",
"executor": "rest_api_executor",
"priority": 60,
"description": "Daily cleanup of vectors/graph nodes for documents deleted from Paperless-ngx",
"enabled": true,
"max_retries": 2,
"timeout_seconds": 900,
"minute": 0,
"hour": 5,
"day_of_month": -1,
"month": -1,
"day_of_week": -1,
"config": {
"method": "POST",
"url": "http://library-desk:8089/maintenance/cleanup/paperless?user=jpmschweitzer&dry_run=false",
"payload": {},
"auth": {
"type": "bearer",
"token": "${LIBRARY_API_KEY}"
}
}
}
4. Disable test_example_task
Not a new task: the leftover example task must be disabled (not deleted, so its history is preserved).
PUT ${SCHEDULER_URL}/tasks/test_example_task
Content-Type: application/json
{"enabled": false}
Related (already registered / in-process)
knowledge_consolidation— every 30 minutes, POST/consolidate/knowledge(already registered; after the Phase C consolidation repair its runs logsearches_processedandduration_ms, and searches are no longer consumed while the LLM is unavailable).- Redis job-set cleanup — runs in-process inside library-desk
(hourly
job_cleanup_loopstarted at app startup); no Scheduler task needed.