Skip to main content

Cron Scheduled

A complete worked example of a job-mode template with metadata.schedule_config. Use as a starting point for any "run this on a schedule" need.

Example: nightly Postgres → S3 backup

services:
backup:
image: postgres:17-alpine
environment:
PGHOST: db.example.internal
PGUSER: backup_role
PGPASSWORD: placeholder
PGDATABASE: app
AWS_ACCESS_KEY_ID: key-id
AWS_SECRET_ACCESS_KEY: placeholder
AWS_DEFAULT_REGION: us-east-1
S3_BUCKET: backups
command:
- /bin/bash
- -ec
- |
# install aws cli (alpine image; do it inline to keep template small)
apk add --no-cache aws-cli ca-certificates
TS=$$(date -u +%Y%m%dT%H%M%SZ)
FILE="/tmp/$${PGDATABASE}-$${TS}.sql.gz"
echo "Dumping $$PGDATABASE..."
pg_dump --no-owner --no-privileges | gzip -c > "$$FILE"
echo "Uploading to s3://$$S3_BUCKET/..."
aws s3 cp "$$FILE" "s3://$$S3_BUCKET/$$(basename "$$FILE")"
echo "Done."
restart: "no"
labels:
fibe.gg/job_watch: "true"

x-fibe.gg:
metadata:
description: "Nightly Postgres backup to S3"
category: "Operations"
job_mode: true
schedule_config:
enabled: true
cron: "0 3 * * *" # 03:00 UTC daily
marquee_id: 1
variables:
PG_HOST:
name: "Postgres host (production DB endpoint)"
required: true
path: services.backup.environment.PGHOST
PG_USER:
name: "Postgres user"
required: true
default: "backup_role"
path: services.backup.environment.PGUSER
PG_PASS:
name: "Postgres password"
required: true
secret: true
sensitive: true
path: services.backup.environment.PGPASSWORD
PG_DB:
name: "Postgres database"
required: true
path: services.backup.environment.PGDATABASE
AWS_KEY_ID:
name: "AWS access key ID"
required: true
secret: true
path: services.backup.environment.AWS_ACCESS_KEY_ID
AWS_SECRET:
name: "AWS secret access key"
required: true
secret: true
sensitive: true
path: services.backup.environment.AWS_SECRET_ACCESS_KEY
AWS_REGION:
name: "AWS region"
required: true
default: "us-east-1"
path: services.backup.environment.AWS_DEFAULT_REGION
S3_BUCKET:
name: "S3 bucket name"
required: true
path: services.backup.environment.S3_BUCKET

What this does

  • Every day at 03:00 UTC, Fibe creates a new Playground from this template on Marquee 1.
  • The backup container starts. It dumps Postgres, gzips, uploads to S3.
  • fibe.gg/job_watch: "true" says: "watch this service's exit code". Exit 0 → success. Exit non-zero → failure.
  • After the container exits, Fibe tears down the Playground.
  • The run result is logged for inspection via fibe_resource_list(resource: "trick", ...).

Why this is the right shape

DecisionReason
No fibe.gg/portJob-mode strips exposure labels before launch
fibe.gg/job_watch: "true"One watched service decides success/failure
restart: "no"Required behavior; runtime forces it anyway
command: inline shellSelf-contained — no Dockerfile build needed
$$var__NAME for secretsGenerated via launcher, masked with secret: true
Cron in UTCDefault; if the org needs local time, document explicitly

Variant: cleanup old data

services:
cleanup:
image: alpine:3
command:
- /bin/sh
- -ec
- |
apk add --no-cache curl
echo "Calling cleanup endpoint..."
curl -fSL -X POST -H "Authorization: Bearer $$API_TOKEN" \
"https://api.example.com/internal/cleanup-old?days=30"
environment:
API_TOKEN: placeholder
labels:
fibe.gg/job_watch: "true"
restart: "no"

x-fibe.gg:
variables:
API_TOKEN:
name: "API token"
required: true
secret: true
sensitive: true
path: services.cleanup.environment.API_TOKEN
metadata:
description: "Weekly cleanup — calls internal endpoint to purge data older than 30 days"
category: "Operations"
job_mode: true
schedule_config:
enabled: true
cron: "0 4 * * 0" # weekly, Sunday 04:00 UTC
marquee_id: 1

Variant: fan-out across props

If you want the same scheduled job to run for several Props (e.g. backups across multiple Player DBs), create one template per Prop, each with its own schedule_config.marquee_id and Prop-specific variables. There is no "for each Prop" in schedule_config — schedule fires one job at a time.

Cron expressions cheat sheet

0 3 * * *        ← 03:00 daily
*/15 * * * * ← every 15 minutes
0 */2 * * * ← every 2 hours
0 9 * * 1-5 ← 09:00 Monday–Friday
0 0 1 * * ← midnight, first of month
0 0 * * 0 ← midnight Sunday

5 fields: min hour day-of-month month day-of-week. Standard POSIX cron syntax. Test with an external tool like https://crontab.guru/ before deploying.

Running on demand (one-off manual)

fibe_resource_mutate(resource: "trick", operation: "trigger", payload: { playspec_id_or_name: ... }) to fire the same template outside the schedule. Useful for testing.

To re-run the last fire: fibe_resource_mutate(resource: "trick", operation: "rerun", payload: { id_or_name: ... }).

Inspecting results

fibe_resource_list(resource: "trick", params: { playspec_id: ... }) shows recent runs. Each has status, started/finished timestamps, exit code, log location.

Pitfalls

  • Missing job_watch — without a watched service the run is "always succeeding" or undefined. Always set on the service whose exit defines outcome.
  • Bash with single $VAR — Compose substitutes $VAR from its env, leaving an empty string if not set. Use $$VAR to escape and get a literal $VAR for the shell to expand.
  • Fibe template $$var__NAME vs shell $$VAR — easy to confuse. $$var__NAME is substituted by Fibe at compile time; $$VAR is $VAR to the shell at runtime.
  • Job exceeding the next cron interval — runs overlap. Make the cron sparse enough or gate with a flock/distributed lock.
  • Cron in wrong timezone — schedule is UTC by default. If the team thinks in local time, document or convert.
  • Missing AWS config / IAM creds — silent S3 upload failure. Log diagnostics in the script.

mode-job-trick, mode-schedule-cron, recipe-random-and-secrets, decide-secrets-and-randoms, reference-x-fibe-gg-namespace.