The fundamental unit of work in Strait.
Jobs define the configuration for a specific task that can be executed. They act as templates for Runs.
Job Model
The Job struct (defined in apps/strait/internal/domain/types.go) contains the following fields:
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (UUIDv7). |
project_id | string | The project this job belongs to. |
group_id | string | Optional ID of the JobGroup for logical organization. |
name | string | Human-readable name of the job. |
slug | string | URL-friendly identifier, unique within a project. |
description | string | Optional detailed description. |
cron | string | 5-field cron expression for automatic scheduling. |
payload_schema | json | JSON Schema to validate incoming trigger payloads. |
tags | map[string]string | Key-value pairs for filtering and metadata. |
endpoint_url | string | The primary HTTP URL where the job payload is sent. |
fallback_endpoint_url | string | Optional URL used if the primary endpoint fails. |
max_attempts | int | Maximum number of retry attempts (default: 3). |
timeout_secs | int | Maximum execution time in seconds (default: 300). |
max_concurrency | int | Per-job limit on simultaneous executing runs. |
execution_window_cron | string | Cron-like expression defining when the job is allowed to run. |
timezone | string | Timezone for cron scheduling (e.g., "UTC", "America/New_York"). |
rate_limit_max | int | Maximum number of runs allowed in the rate limit window. |
rate_limit_window_secs | int | The window size for rate limiting in seconds. |
max_concurrency_per_key | int | Per-key concurrency limit. When set with a run's concurrency_key, limits concurrent active runs sharing the same key. |
rate_limit_keys | []RateLimitKey | Named rate limit configurations. Each entry has name, max, and window_secs. |
default_run_metadata | map[string]string | Default metadata key-value pairs applied to every run created for this job. |
dedup_window_secs | int | Window for deduplicating identical trigger requests. |
enabled | bool | Whether the job is active and can be triggered. |
webhook_url | string | URL to notify when a run reaches a terminal state. |
webhook_secret | string | Secret used to sign webhook payloads (HMAC-SHA256). |
run_ttl_secs | int | Time-to-live for runs before they are considered expired. |
retry_strategy | string | Strategy: exponential, linear, fixed, or custom. |
retry_delays_secs | []int | Array of delays for the custom retry strategy. |
environment_id | string | The environment (e.g., Staging, Production) this job is bound to. |
version | int | Auto-incrementing version number (starts at 1). |
version_id | string | Unique nanoid for this version (ver_k8f2m9x1p3). Changes on every update. |
version_policy | string | How queued runs interact with updates: pin (default), latest, or minor. See Versioning. |
backwards_compatible | bool | Whether the current version is backwards compatible with the previous version. |
created_by | string | Actor ID who created the job (user ID or apikey:<id>). |
updated_by | string | Actor ID who last updated the job. |
on_complete_trigger_workflow | string | Optional workflow slug to auto-trigger when a run completes successfully. |
on_complete_payload_mapping | json | Optional JSON mapping to extract fields from the run result as the triggered workflow's payload. Uses dot-notation paths (e.g., {"user_id": "result.user.id"}). |
created_at | time.Time | Timestamp when the job was created. |
updated_at | time.Time | Timestamp of the last update. |
Slugs and Project Scoping
Jobs are scoped to a project_id. The slug must be unique within that project. This allows for clean URLs and API access patterns like /v1/jobs/{jobID}.
Scheduling and Execution
{
"cron": "0 * * * *",
"timezone": "UTC"
}{
"execution_window_cron": "0 9-17 * * 1-5"
}- Cron: Standard 5-field syntax supported via
robfig/cron/v3. - Execution Windows: Restricts job execution to specific times (e.g., business hours).
Concurrency and Rate Limiting
- Max Concurrency: Limits the number of parallel executions for a single job definition.
- Rate Limiting: Prevents thundering herds by capping the number of runs over a sliding window.
- Deduplication: Uses
dedup_window_secsand an idempotency key to ignore duplicate trigger requests within a short timeframe.
Per-Key Concurrency
When max_concurrency_per_key is set on a job, each run must provide a concurrency_key. Runs sharing the same key are limited to max_concurrency_per_key concurrent active executions. This is useful for per-tenant or per-resource throttling.
For example, setting max_concurrency_per_key: 1 ensures only one run per key executes at a time, creating a per-key serial queue.
Named Rate Limit Keys
The rate_limit_keys field allows defining multiple named rate limits on a single job. Each entry specifies:
name: identifier for the rate limitmax: maximum runs in the windowwindow_secs: window duration in seconds
This extends the flat rate_limit_max/rate_limit_window_secs to support more granular control.
Job Versioning
Every time a job's configuration is updated, the version field is automatically incremented. This ensures that:
- In-flight runs continue using the configuration they were triggered with.
- Historical data remains accurate to the job's state at the time of execution.
Webhook Configuration
Jobs can be configured with a webhook_url and webhook_secret. When a run completes, fails, or times out, a signed POST request is sent to this URL.
Always use the webhook_secret to verify webhook authenticity via X-Strait-Signature + X-Strait-Timestamp (and optionally compatibility X-Webhook-Signature).
Environment Binding
Jobs can be linked to an environment_id. This allows Strait to apply environment-specific overrides, such as changing the endpoint_url when running in a "Staging" vs "Production" environment.
Related Concepts
- Runs: The execution instances of a job.
- Workflows: DAGs that coordinate multiple jobs.
- Job Groups: Logical containers for related jobs within a project.