Skip to content

Scheduling Pipelines

PocketCI can run pipelines automatically on a schedule using cron expressions or fixed intervals. Schedules are defined inline in YAML pipelines and managed via the CLI or API.

Prerequisites

The scheduling feature requires the schedules feature gate, which is not included in the default * wildcard. Enable it explicitly:

bash
pocketci server --allowed-features "*,schedules"

Or via environment variable:

bash
export CI_ALLOWED_FEATURES="*,schedules"
pocketci server

See Feature Gates for more details.

Defining Schedules in YAML

Add a triggers.schedule block to any job in your pipeline YAML:

yaml
jobs:
  - name: nightly-build
    triggers:
      schedule:
        cron: "0 2 * * *"
    plan:
      - task: build
        config:
          image: golang:1.22
          run:
            path: go
            args: [build, ./...]

  - name: health-check
    triggers:
      schedule:
        every: "15m"
    plan:
      - task: check
        config:
          image: curlimages/curl
          run:
            path: curl
            args: [-f, "http://app:8080/health"]

Each job can have at most one schedule trigger. Use either cron or every, not both.

Cron Expressions

Standard 5-field cron format: minute hour day-of-month month day-of-week.

ExpressionDescription
0 2 * * *Daily at 2:00 AM
*/15 * * * *Every 15 minutes
0 9 * * 1-5Weekdays at 9:00 AM
0 0 1 * *First day of each month
30 6 * * 0Sundays at 6:30 AM

Interval Expressions

Go duration strings specify a fixed interval between runs:

ExpressionDescription
5mEvery 5 minutes
1hEvery hour
12hEvery 12 hours
1h30mEvery 90 minutes

The next run is computed as last_run + interval. If a schedule has never run, the first execution happens one interval after the pipeline is set.

How the Scheduler Works

  1. A background goroutine polls the database every 10 seconds for due schedules.
  2. Due schedules are claimed atomically using UPDATE ... RETURNING, preventing double-fire in multi-instance deployments.
  3. After claiming, the scheduler triggers the pipeline and computes the next run time.
  4. If the execution queue is full, the trigger is skipped and retried at the next poll interval.

Job Targeting

When a schedule is attached to a specific job, only that job (and its downstream dependents) runs. This is visible in the run metadata:

  • trigger_type is set to schedule
  • triggered_by shows schedule:<schedule-name>

Managing Schedules

CLI

List all schedules for a pipeline:

bash
pocketci pipeline schedule ls my-pipeline --server http://localhost:8080

Pause a schedule to temporarily stop it from firing:

bash
pocketci pipeline schedule pause my-pipeline nightly-build \
  --server http://localhost:8080

Unpause to resume:

bash
pocketci pipeline schedule unpause my-pipeline nightly-build \
  --server http://localhost:8080

See Pipeline Schedule CLI for full reference.

API

  • GET /api/pipelines/:id/schedules — list all schedules
  • PUT /api/schedules/:id/enabled — pause or unpause

See Schedules API for full reference.

Triggering Pipelines from JavaScript

The triggerPipeline() global function allows a running pipeline to programmatically trigger another pipeline:

typescript
// Trigger another pipeline by name
const runId = await triggerPipeline("deploy-staging");

// Target specific jobs
const runId = await triggerPipeline("integration-tests", {
  jobs: ["api-tests", "ui-tests"],
});

// Pass arguments
const runId = await triggerPipeline("release", {
  args: ["--version=2.0.0"],
});

Signature

typescript
triggerPipeline(
  pipelineName: string,
  options?: {
    jobs?: string[];
    args?: string[];
  }
): Promise<string>

Returns a Promise that resolves with the triggered run's ID.

Interaction with the Execution Queue

Scheduled triggers respect the server's concurrency limits. If both in-flight slots and the queue are full, the scheduled trigger is skipped for that poll cycle and retried on the next interval. Configure queue capacity with --max-queue-size (see Execution Queue).