Guides

Jobs and CronJobs

Run one-off Jobs and scheduled CronJobs on nyxory — batch work, migrations, nightly data jobs — deployed by your agent the same way it deploys an app.

Not everything is a server. A migration that runs once ahead of a cutover, a nightly database dump, an hourly data-consolidation pass, a cache warm — this is run-to-completion work: it starts, does the job, exits 0, and it’s done. nyxory runs it as a first-class workload. A Job runs once; a CronJob runs on a schedule. Your agent deploys either one exactly the way it deploys an app — same nyx_deploy_manifests path, same App ownerRef, same instance label — and this is the scheduling primitive agents compose recurring operations from.

Deploying one

Two steps, the same as any app minus the server parts:

  1. Build the image. nyx_build_and_push_image from your repo — the same build path.
  2. Deploy the manifest. nyx_deploy_manifests with the Job or CronJob spec, carrying the App ownerRef like every other owned object.

A Job or CronJob gets no Service, no domain, and no probes — there’s nothing to route traffic to and nothing to health-check. The only signal that matters is whether the run completed.

Scheduling recurring work

A CronJob runs a container on a schedule you set, which makes it the workhorse behind day-to-day operations an agent sets up once and then leaves running:

  • A nightly database backup to your object store (until unattended platform backups are on by default).
  • An hourly data-consolidation or sync job — pull, transform, write, exit.
  • A scale-down at night, scale-up in the morning — a CronJob that runs kubectl scale (see Scaling and RAM).
  • A periodic cache warm or cleanup pass.

Your agent writes the schedule (spec.schedule in standard cron syntax) and applies it; from there the container fires on its own. The work in the container is yours to define — the CronJob just guarantees it runs on time.

Verifying a run

Don’t wait for a 1/1 Ready pod and don’t curl anything — neither ever comes. Check completion status, then read that pod’s logs for the actual result.

Note: A Job is healthy when status.succeeded: 1. A CronJob is healthy when lastSuccessfulTime is after lastScheduleTime. A still-running pod means “in progress,” not broken; a pod that’s disappeared means “already finished,” not failed — completion status is what tells them apart.

Making it safe to re-run

The platform doesn’t make re-runs idempotent — the job’s own logic has to, because a redeploy or a missed tick can run the work twice. Guard it: append-only writes, skip-if-done checks, INSERT ... ON CONFLICT DO NOTHING, or a migration tool that tracks which versions already ran.

Two spec settings keep a schedule from causing damage under load — a firing CronJob draws on the same namespace RAM/CPU quota as any running Deployment, so set real requests/limits on it too:

  • concurrencyPolicy: Forbid (or Replace) stops overlapping ticks from stacking up if one run outlasts its interval.
  • backoffLimit caps retries so a broken job can’t spawn pods indefinitely.

Relevant tools: nyx_build_and_push_image, nyx_deploy_manifests, nyx_shell (for kubectl delete job/<name> and status/log reads).

Ask any AI about nyxory