Gyro Containers: one-off jobs and database migrations
1. How it works
- The job starts from the image of the running version of the service you pick. The image is pinned by digest: even if a tag such as
:latestmoves meanwhile, exactly the running version is used. - The service's variables and secrets come along, so connection settings like
DATABASE_URLneed no second copy. - The command replaces the image ENTRYPOINT and is sent as a list. For shell features (
&&,>,|) writesh -c "…". Without a command the image's own command runs. - A job has no ports and no health checks and stops when done. A failed job is not retried (so a migration never runs twice).
- Default size = the service's; time limit 30 minutes (choose 10 seconds to 6 hours). When the time is up the job is stopped.
- The last 50 jobs are kept with their output (last 2,000 lines). Secret values of the service show as
****.
2. From the panel
- Open the Jobs tab of your service and press Run job.
- Pick the Service (image, variables and secrets come from it).
- Type the Command, e.g.
npm run migrate,php artisan migrate --forceorpython manage.py migrate. - Change the time limit, vCPU and memory if needed, then press Start.
- The state moves Starting → Running → Succeeded / Failed. Output shows the log live; Stop ends a running job.
3. CLI, API and AI assistants
# follow the output; the CLI exits with the job's exit code (124 = time limit reached)
gyro container run 12345 --service api --follow -- npm run migrate
# with shell features and a 10 minute limit
gyro container run 12345 --service web --wait --time-limit 10m -- sh -c "php artisan migrate --force && php artisan db:seed --force"
gyro container jobs 12345 # recent jobs
gyro container job logs 12345 jt0abc12def3 # output of one job
API: POST /cloud/containers/{id}/services/{service}/run with {"command": ["npm","run","migrate"], "timeout_seconds": 900}; state GET /cloud/containers/{id}/jobs/{job}, output .../logs, stop DELETE /cloud/containers/{id}/jobs/{job}. Send an Idempotency-Key header to retry safely. Gyro MCP tools: run_container_job, get_container_job, list_container_jobs, stop_container_job.
4. Before every pipeline deploy
Add release to gyro-pipeline.yml:
image: api
deploy:
services: [api]
release: ["npm", "run", "migrate"] # with the new image, before the deploy
After the build the job runs with the new image and the settings of the first target service; the run waits in state Running release job (releasing). With approval on, the job runs after the approval. When it succeeds the deploy starts; when it fails nothing is deployed, your running version stays and the run ends with error release_failed. The job's output is on the Jobs tab with the run number.
5. Limits and price
| Node plans | Serverless | |
|---|---|---|
| Jobs at the same time | 2 on plans up to 2 vCPU, 3 otherwise | 2 |
| Where it runs | On your own nodes, in the free capacity next to your services | On the shared sandboxed pool |
| Price | No extra charge | Like a task, per vCPU-second / GB-second; billing line <service>-job |
- Without free capacity the job is refused: reduce its vCPU/memory, stop a copy or upgrade the plan.
- The parallel job limit can be raised with a support ticket (
gyro limitsshows it). - A failed or timed out job sends the job_failed notification (your email, SMS, Telegram and webhook channels on the Alerts tab).
6. FAQ
Can a migration run twice?
No. A failed job is never retried automatically; running it again is your decision.
Which image is used?
For a job started by hand, the service's running version (digest). If the service has no running copy the configured tag is used and the panel says "by tag". In the pipeline the newly built image is used.
Can I use < , > , && in the command?
Yes. The command arrives unchanged; for redirection and chaining write sh -c "…".
Does a job affect my service?
Your service keeps running. The job is a separate container that only shares the same capacity.
Are scheduled jobs (cron) available?
Not yet; start a one-off job from your own scheduler with the CLI or API.
Thanks for your feedback!
