Scheduled Jobs
CRON-based scheduled jobs that invoke HTTP endpoints on your services. Configured in infrastructure.json, deployed via CLI, with provider-specific infrastructure generated automatically.
How it works
Scheduled jobs are regular NestJS controller endpoints. In cloud, the provider's native scheduler calls them on a CRON schedule with authentication. Locally, you trigger them manually.
Configuration
Add jobs to .tsdevstack/infrastructure.json under the target environment:
Auth template: the API key usage job
Projects on the auth template need one job in every cloud environment: sync-api-key-usage. It saves API key usage totals to Postgres and rebuilds the key index when Redis lost it.
It is not added for you. infra:generate warns for each environment that lacks it and prints the entry to add, with your auth-service prefix. See API Keys for what it does.
Service-side implementation
Job endpoints use SchedulerGuard from @tsdevstack/nest-common and are excluded from the OpenAPI spec so Kong doesn't expose them publicly:
Two layers of protection:
@ApiExcludeController()— keeps routes out of the OpenAPI spec, so Kong never creates a public route for themSchedulerGuard— validates that the request comes from the cloud scheduler, not an external source
Authentication
The guard validates requests differently per provider:
Local development
Scheduled jobs don't run on a schedule locally. Trigger them manually:
The SchedulerGuard skips validation in local mode, so no authentication headers are needed.
CLI commands
In CI, all flags must be explicit — no interactive prompts.
Provider architecture
GCP — Cloud Scheduler
Cloud Scheduler makes HTTP requests directly to the Cloud Run service URL with an OIDC token. Service URLs are computed from the project number (deterministic), so the Terraform has no dependency on existing deployments.
AWS — EventBridge + Lambda
EventBridge Schedule triggers a Job Invoker Lambda. The Lambda retrieves the job secret from Secrets Manager, then calls the service endpoint via Cloud Map DNS inside the VPC. Services on AWS always run at least one task, so there is nothing to wake first.
Azure — Container App Jobs
Azure runs a lightweight curl container on the CRON schedule. The container reads the job secret from its environment (injected from Key Vault) and calls the target Container App.
Deployment
Scheduler infrastructure is included in the main infra:generate output. A full infra:deploy creates everything automatically:
To update a schedule without a full deploy: