Production-hardened backend service for distributed data discovery and access routing in a SRC-like environment.
- FastAPI application with modular service layers (
routers,services,ranking,vo). - PostgreSQL metadata catalog with ObsCore-inspired
datasetsand distributed placement viadataset_replicas. - Ranking policy filters disabled/unavailable nodes and supports fallback to next candidate.
- Access endpoint returns routing metadata;
/soda/executeperforms real node-local FITS cutouts (compute-next-to-data) without moving the dataset. - Structured JSON logging, request tracing, Prometheus metrics, and health endpoints.
Funded by INAF under the Astrophysics Fundamental Research Grant (Techno Grant).
- Discovery:
/discovery/search,/discovery/dataset/{obs_id} - Canonical DataLink descriptor:
/datalink/{obs_id} - TAP sync ObsCore compatibility profile:
/tap/sync - TAP async job profile:
/tap/async - SODA sync validation endpoint:
/soda/sync - SODA cutout execution (node-local, compute-next-to-data):
/soda/execute - Metadata-cache staging:
/staging/jobs - Provenance/PID/citation endpoint:
/provenance/{obs_id} - Federated discovery peer queries:
/federation/search - Access routing:
/access/{obs_id} - Operational endpoints:
/availability,/health/db,/metrics,/capabilities - VO-aligned metadata and capability model (without claiming full TAP/DataLink/SODA server compliance)
- Internal ingestion API guide:
docs/internal_ingestion.md - Ingestion guide:
docs/ingestion.md - Discovery query guide:
docs/discovery_queries.md - Access DataLink-like guide:
docs/access_datalink.md - Canonical DataLink endpoint guide:
docs/datalink_endpoint.md - TAP sync guide:
docs/tap_sync.md - SODA sync guide:
docs/soda_sync.md - SODA execution (compute-next-to-data) guide:
docs/soda_execution.md - Install guide:
docs/install.md - Runbook:
docs/runbook.md - VO alignment notes:
docs/vo_alignment.md - Architecture notes:
docs/architecture.md
All runtime configuration is environment-driven.
Required in staging and production:
SKAVA_DATABASE_URLSKAVA_PUBLIC_BASE_URL
Core variables:
INTERNAL_API_KEY(required for internal ingestion control API)SKAVA_ACCESS_TOKENS(optional comma-separated bearer tokens for discovery/access endpoints)SKAVA_FEDERATED_SRC_URLS(optional comma-separated peer base URLs)SKAVA_FEDERATION_TIMEOUT_SECONDSSKAVA_ENV=dev|staging|productionSKAVA_LOG_LEVEL=DEBUG|INFO|WARNING|ERRORSKAVA_DB_POOL_SIZESKAVA_DB_MAX_OVERFLOWSKAVA_DB_POOL_TIMEOUTSKAVA_DB_POOL_RECYCLESKAVA_DB_CONNECT_RETRIESSKAVA_DB_CONNECT_RETRY_DELAY
See .env.example for defaults.
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
# PostgreSQL must be available at SKAVA_DATABASE_URL
alembic upgrade head
python -m app.seed
uvicorn app.main:app --reloaddocker compose up --buildService URL: http://localhost:8000
Includes:
skava-discoverypostgresreverse-proxy(nginx)
docker compose -f docker-compose.staging.yml up --buildStaging ingress URL: http://localhost:8080
curl 'http://localhost:8000/availability?include_nodes=true'
curl 'http://localhost:8000/health/db'
curl 'http://localhost:8000/metrics'
curl 'http://localhost:8000/discovery/search?COLLECTION=skava-demo&DPTYPE=image'
curl 'http://localhost:8000/discovery/search?POS=CIRCLE%20180%20-30%200.2&BAND=1.3e-6%201.4e-6&TIME=59003.1%2059003.4'
curl 'http://localhost:8000/discovery/dataset/dataset-3'
curl 'http://localhost:8000/datalink/dataset-3'
curl 'http://localhost:8000/datalink/dataset-3?RESPONSEFORMAT=application/x-votable+xml'
curl 'http://localhost:8000/tap/sync?QUERY=SELECT%20TOP%201%20*%20FROM%20ivoa.ObsCore%20WHERE%20obs_id%20%3D%20%27dataset-3%27'
curl -X POST 'http://localhost:8000/tap/async' -F 'QUERY=SELECT TOP 1 * FROM ivoa.ObsCore WHERE obs_id = '\''dataset-3'\'''
curl 'http://localhost:8000/soda/sync?ID=dataset-3&POS=CIRCLE%20103%20-23%200.05&BAND=1.3e-6%201.4e-6&TIME=59003.1%2059003.3'
curl -X POST 'http://localhost:8000/soda/execute?ID=dataset-3&POS=CIRCLE%20103%20-23%200.05' -o cutout.fits
curl -X POST 'http://localhost:8000/staging/jobs?ID=dataset-3'
curl 'http://localhost:8000/provenance/dataset-3'
curl 'http://localhost:8000/federation/sources'
curl 'http://localhost:8000/access/dataset-3'Discovery semantics (production-oriented):
POSsupportsCIRCLE ra dec radiuswith center-based overlap approximation usings_ra/s_decand optionals_fov.BANDrequiresmin maxand overlaps againstem_min/em_max.TIMErequiresmin maxand overlaps againstt_min/t_max.limitandoffsetbound result sets for production-safe scans.SPATIAL_CELLcan filter the lightweight HEALPix/MOC-ready spatial cell key exposed in metadata.
Access semantics (DataLink):
/datalink/{obs_id}is the canonical access descriptor endpoint (JSON by default)./datalink/{obs_id}?RESPONSEFORMAT=application/x-votable+xmlreturns a conformant IVOA DataLink VOTable: standard{links}columns with spec UCDs,#-prefixed semantics terms, and a SODA cutout service descriptor (utype="adhoc:service") — consumable by pyvo/TOPCAT./access/{obs_id}is a compatibility facade that delegates to/datalink/{obs_id}and preserves legacy fields.
TAP sync semantics:
/tap/syncprovides a minimal ObsCore compatibility profile.- Supported ADQL is intentionally constrained to
SELECTfromivoa.ObsCorewith equality predicates forobs_id,obs_collection, anddataproduct_type. - Default output is VOTable; use
FORMAT=jsonfor JSON. /tap/asyncpersists TAP jobs and returns job status/results. In the current profile jobs execute immediately; the storage model is ready for a future worker queue.
Staging semantics:
/staging/jobscreates a metadata-cache staging handoff and returns the selected access URL.- This does not yet perform byte-level data movement; it is the control-plane primitive for future prefetch/staging workers.
Federation semantics:
/federation/searchqueries configured peer/discovery/searchendpoints usingSKAVA_FEDERATED_SRC_URLS.- Failures are reported per source without failing the whole response.
SODA semantics:
/soda/syncvalidatesID,POS,BAND,TIME,RESPONSEFORMATand resolves routing (JSON descriptor)./soda/executeperforms a real byte-level FITS cutout when the dataset's best node exposes a co-located VisIVO backend (Node.visivo_backend_url) serving afile://replica: SKAVA delegates to the node's/v1/datasets/cutout, the cutout is computed on the node, andapplication/fitsis streamed back (compute-next-to-data).- When no co-located backend is available,
/soda/executefalls back to a metadata-cache staging handoff (legacy behaviour). - A reachable backend that fails the cutout surfaces as
502 backend_execution_failed. - See
docs/soda_execution.mdfor the delegation design and the backend endpoint.
Example discovery response (abridged):
{
"metadata": {"obs_id": "dataset-3", "obs_collection": "skava-demo"},
"replicas": [{"code": "A"}, {"code": "B"}],
"best_node": "B",
"access_url": "http://localhost:8000/access/dataset-3"
}Example error response:
{
"error": {
"code": "invalid_query",
"message": "BAND contains non-numeric values"
},
"request_id": "..."
}pytestThis service is VO-aligned in production use:
- DataLink is served both as JSON and as a conformant IVOA DataLink VOTable descriptor;
- SODA cutout execution (
POS/BAND) is implemented via compute-next-to-data delegation to a node's co-located VisIVO backend, with a staging-handoff fallback.
It intentionally does not yet implement full TAP async / full ADQL, asynchronous DataLink/SODA job services, or full standard-server compliance across all operations.