Pipeline runs

Follow pipeline runs and their steps, cancel and retry runs, and decide reviews.

Pipelines are in preview, and Editframe enables them for each organization. Until they are enabled for your organization, every pipeline route returns 404. To ask for access, email hello@editframe.com.

A run processes one video file through one version of a pipeline. This page describes how a run and its steps progress, how to cancel and retry runs, and how to decide reviews.

Follow a run

getPipelineRun returns the run with every step of its pipeline version, in definition order:

js
import { Client, getPipelineRun } from "@editframe/api/pipelines";

const client = new Client(process.env.EDITFRAME_API_KEY);
const run = await getPipelineRun(client, runId);

console.log(run.status, run.error);
for (const step of run.steps) {
  console.log(step.step_key, step.status, step.attempt, step.watermark_ms);
}
bash
npx editframe pipelines runs get RUN_ID --watch
npx editframe pipelines runs list --status failed --pipeline-id PIPELINE_ID

A step that has not been scheduled yet has the status pending and an id of null. For a segment step, watermark_ms is how far through the media its output is final.

listPipelineRuns returns runs newest first, and takes status, pipeline_id, file_id and batch_id filters. For notifications instead of polling, subscribe to the pipeline webhook topics.

Run statuses

succeeded, failed, filtered and cancelled are final. isPipelineRunTerminal(run) returns true for them.

What filtered means

A run is filtered when a filter or a review stopped one of its branches: a filter's predicate was false, a reviewer rejected, or a review expired with on_expiry: "reject". The stopped step is skipped, and every step that needs it, directly or indirectly, is also skipped. filtered is not an error, and the outputs of the steps that succeeded remain available.

A pipeline with two complementary filters always ends filtered, because the branch that is not taken is skipped.

Step statuses

Automatic retries

Each step, and each window of a segment step, has 3 attempts. After a retryable failure, Editframe waits 10 seconds, doubles the wait for each later attempt up to 10 minutes, and starts the next attempt. A longer Retry-After from your endpoint replaces the wait. Timeouts, connection errors and 408, 429 and 5xx endpoint responses are retryable.

When a step fails without a retry, Editframe cancels the unfinished steps and the run fails. run.error has the message, the code and the step_key of the failed step.

Cancel a run

js
import { cancelPipelineRun } from "@editframe/api/pipelines";

await cancelPipelineRun(client, runId);
bash
npx editframe pipelines runs cancel RUN_ID

The request returns 202 with the run. The run becomes cancelled asynchronously: unfinished steps are cancelled, and no other steps start. A run that has succeeded, failed or ended filtered returns 409 run_not_cancellable.

Retry a run

js
import { retryPipelineRun } from "@editframe/api/pipelines";

await retryPipelineRun(client, runId);
bash
npx editframe pipelines runs retry RUN_ID --watch

Only failed and cancelled runs can be retried. Other runs return 409 run_not_retryable. A retry runs the failed and cancelled steps and windows again, each with 3 more attempts. Steps and windows that succeeded keep their outputs. A review that failed when it expired opens a new review task.

The request returns 202 with the run, and the run continues asynchronously. Repeated retry requests for the same failure count as one retry.

Reviews

A review step opens a review task and waits in waiting_review. List the open reviews, oldest first:

js
import { listPipelineReviews, getPipelineReview } from "@editframe/api/pipelines";

const { reviews } = await listPipelineReviews(client, { status: "pending" });
const review = await getPipelineReview(client, reviews[0].id);

console.log(review.instructions, review.expires_at, review.input_namespaces);
bash
npx editframe pipelines reviews list --status pending
npx editframe pipelines reviews get REVIEW_ID

A review has the status pending, approved, rejected or expired, the run_id, file_id and step it belongs to, the instructions, on_expiry and expires_at of the step, and the recorded decision. input_namespaces lists the namespaces of the steps the review step needs, directly or indirectly. Read their outputs with getPipelineRunOutputs(client, review.run_id, namespace).

Approve

An approval can correct annotations. The corrected annotations, and every kind in reviewed_kinds, replace the annotations of those kinds from earlier steps for every later step. A kind in reviewed_kinds without annotations leaves later steps with none of that kind. Kinds that you do not name keep their original annotations.

js
import { approvePipelineReview } from "@editframe/api/pipelines";

await approvePipelineReview(client, reviewId, {
  metadata_patch: {
    annotations: [
      {
        kind: "face",
        start_ms: 846000,
        end_ms: 849000,
        keyframes: [
          { t_ms: 846000, x: 0.41, y: 0.22, w: 0.12, h: 0.18 },
          { t_ms: 849000, x: 0.45, y: 0.21, w: 0.12, h: 0.18 },
        ],
      },
    ],
    reviewed_kinds: ["face", "plate"],
  },
});
bash
npx editframe pipelines reviews approve REVIEW_ID --patch corrections.json

The review step succeeds. Its output has the corrected annotations and the metadata decision, decided_by, decided_at, review_task_id and reviewed_kinds.

Reject

js
import { rejectPipelineReview } from "@editframe/api/pipelines";

await rejectPipelineReview(client, reviewId, { reason: "Not dashcam footage" });
bash
npx editframe pipelines reviews reject REVIEW_ID --reason "Not dashcam footage"

A rejection skips the review step and every step after it, so the run ends filtered. reason has at most 2000 characters.

Decision rules

The HTTP route is POST /api/v1/pipeline-reviews/:id/decision with { "decision": "approved", "metadata_patch": … } or { "decision": "rejected", "reason": … }. It returns 202 with the review. The review stays pending until the run applies the decision.

When nobody decides before expires_at, the step's on_expiry setting applies. See Review steps.

Dashboard

When pipelines are enabled for your organization, the dashboard navigation has a Pipelines group with the Pipelines, Runs and Reviews pages. The pages update while runs are active.

  • Pipelines shows, for the last 24 hours, 7 days or 30 days, how many runs finished and succeeded, how many are running, and how many reviews wait for a decision. Under Needs attention it groups failed runs by pipeline, step and error code, and links to them. Each pipeline lists its steps, its mix of finished runs and its median run time.
  • A pipeline's page draws the steps of one version as stations. Each station shows how many runs are queued, working or waiting at the step now, and how the step ended in the chosen window: succeeded, failed, filtered out, rejected, expired or not run. A note names the step with the most waiting work. Select a station to open its runs, or a count under Steps to open the runs whose step is in that state. Choose a version to see its flow and definition.
  • Runs lists runs newest first. Filter them by status, pipeline, step and step status, and creation time. Admins and editors can select up to 100 runs to cancel or retry them together, or retry every failed run that matches the filters, up to the newest 500.
  • A run's page shows the step graph, a timeline of the steps, and for a selected step its attempts, errors and events. It also lists the webhook events about the run and its steps, with their delivery attempts. Admins and editors can cancel or retry the run.
  • Reviews lists open reviews oldest first, with their instructions and expiry. On a review's page, admins and editors can remove annotations, correct their times and labels, and then approve, or reject with an optional reason.

Members with the Reader role can view the pages but cannot act.