Skip to main content

One-off jobs

Run a standalone command from a deployed Bex service image, inspect its status, and understand which service settings are not inherited.

Share
Last updated on September 23, 2026
On this page

A one-off job runs a command in a separate container using an existing service's image. Use it for a finite task whose tools and required files are already in that image. It is distinct from a scheduled cron job, a pre-deploy command, or an SSH session in a running service.

Check the execution environment first

The current Bex job implementation copies the service's resolved image, falling back to its configured image if no resolved image is available. It does not copy the service's environment variables, secret files, persistent disks, registry pull credentials, or CPU/memory requests into the job. The container still has any environment and files built into its image.

This differs from Render's service-configuration inheritance. Do not use a service's working database connection as proof that a one-off job can run its migration command. Do not put credentials in startCommand: commands are saved in job history. Private images may fail to pull without separately available cluster credentials.

The API accepts and records planId, but the current job creation path does not apply it as container resource settings. Namespace policies may impose their own limits. Do not use that field as a resource-sizing guarantee.

Your installation needs configured control-plane storage (BEX_CP_DB_URI) and Kubernetes access. Without that storage, the job API returns 503. Creating a job requires developer or admin access; viewing requires resource-read access, and cancellation requires operate access. See workspace roles.

Create a job

Use an API bearer token, the API URL for your installation, and a service ID returned by Bex. The image must be available to the cluster and contain sh and the command's dependencies.

Start with a harmless command to check the execution path:

bash
curl --fail-with-body --silent --show-error \
  -X POST "$BEX_API_URL/v1/services/$SERVICE_ID/jobs" \
  -H "Authorization: Bearer $BEX_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"startCommand":"printf \"one-off job ready\\n\""}'

Save the returned job id as JOB_ID. The response includes serviceId, startCommand, planId, status, and timestamps as they become available. A 201 response is not proof of execution: job creation can return a record already marked failed if Kubernetes creation failed.

Observe completion

bash
curl --fail-with-body --silent --show-error \
  "$BEX_API_URL/v1/services/$SERVICE_ID/jobs/$JOB_ID" \
  -H "Authorization: Bearer $BEX_TOKEN"

Poll periodically, with a timeout appropriate to the task, until status is succeeded, failed, or canceled. pending and running are not terminal. List and get operations refresh nonterminal status from Kubernetes, but a temporary cluster error can leave the last known status visible.

List history with GET /v1/services/{id}/jobs. It returns an array of {job, cursor} entries. Use the returned cursor for subsequent pages. Supported filters include status, createdBefore, createdAfter, startedBefore, startedAfter, finishedBefore, finishedAfter, and limit.

Bex creates jobs with no automatic retry and no explicit job execution deadline. Finished Kubernetes jobs are eligible for cleanup after one hour; this is not a promise of one hour of application-log retention. An installation administrator can inspect the job and pod logs in the service's namespace. Do not assume the service log endpoint includes one-off job output.

Cancel or retry deliberately

bash
curl --fail-with-body --silent --show-error \
  -X POST "$BEX_API_URL/v1/services/$SERVICE_ID/jobs/$JOB_ID/cancel" \
  -H "Authorization: Bearer $BEX_TOKEN"

Cancellation requests deletion of the Kubernetes job and marks its record canceled. Verify that the pod and any external work have stopped before starting a replacement. Canceling an already terminal job returns 409. Cancellation does not reverse external writes that the command already made.

A retry is a new job. Inspect partial effects before creating it, and make the task safe to repeat. For failures, distinguish an unavailable job service, a missing image, an image-pull failure, a missing shell/tool, and a command failure. Use audit logs to investigate who requested an operation; verify its actual result in job status and in the system the command changed.

Was this page helpful?

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex