Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

Job clients

Trigger a public job, retain its run ID, and watch or control that run.

Trigger a job through the generated client, then use its run handle to observe progress and completion. Only jobs with a client policy appear. Triggering one admits work; the returned handle identifies a run and is not the completed result:

Install the frontend client and development CLI in the caller’s package first. Submit with client.jobs.exportOrders.trigger({ input: { orderIds }, options: { operationId } }), then read client.jobs.exportOrders.runs.get({ runId: accepted.runId }). The caller installs no provider SDK; those dependencies belong to the backend’s selected job binding.

Keep accepted.runId and operationId so a later page load or retry can inspect the same run. The app must authorize the caller for this job; a typed client alone does not grant access.

Use from React

The defineJob example names this job exportOrders and exposes trigger, get, list, and watch. After frontend setup and pulling that backend’s contract, render this component under RelkitClientProvider:

"use client";

/** Submits one commerce export and observes the accepted run without replaying an uncertain submission. */
import { useJobRun, useJobTrigger, useRelkitClient } from "@relkit/client/react";

/** Keeps the accepted receipt separate from the task's eventual output.
 * @returns One explicit submission button and its receipt, observation, or failure state. */
export function ExportOrders() {
  const { status } = useRelkitClient();
  const submit = useJobTrigger("exportOrders");
  const run = useJobRun("exportOrders", submit.data ? { runId: submit.data.runId } : {});

  return (
    <section>
      <button
        disabled={status !== "ready" || !submit.isIdle}
        onClick={() => submit.mutate({ input: { orderIds: ["order-1"] } })}
      >
        Export orders
      </button>
      {submit.isPending && <p role="status">Submitting…</p>}
      {submit.isError && (
        <p role="alert">{String(submit.error)}. Check the outcome before submitting again.</p>
      )}
      {submit.data && <p>Run ID: {submit.data.runId}</p>}
      <p role="status">
        Connection: {run.connection}; run: {run.run?.status ?? "not accepted"}
      </p>
    </section>
  );
}

The hook selector is the job’s public name, exportOrders, rather than its stable backend ID orders.export-orders. useJobTrigger supplies managed operation identity and retains pending receipt metadata. useJobRun waits for an accepted runId; mounting it does not submit a job. Persist that receipt in your application’s own UI state if the page must restore it after navigation.

Client API Backend policy required Use
useJobTrigger trigger Submit typed task input and receive a run handle.
useJobRun / watchJobRun watch Observe only the fields selected by the job’s client policy.
useJobCancel cancel Send an explicit control with runId and operationId.
useJobRetry retry Ask the provider to retry a run explicitly.
watchJobStream streams and a declared named stream Read the run’s named content stream with its own lifecycle.

Cancel, retry, and named streams are not exposed by this example’s policy. Declare the needed operations on the backend and pull a new contract before using them. Generated types also restrict which run fields the frontend can read. For an uncertain write, follow recovery guidance; do not turn reconnect into automatic resubmission.

Watch one accepted run

watchJobRun uses the accepted run ID. This public API example subscribes to state changes, connects once, and disposes the watcher when its caller is finished:

import { createClient } from "@relkit/client";
import { watchJobRun } from "@relkit/client/jobs";

export async function watchExport(runId: string): Promise<() => Promise<void>> {
  const client = createClient({ baseUrl: "http://127.0.0.1:3000" });
  const watch = watchJobRun(client, "exportOrders", { runId });
  const unsubscribe = watch.subscribe(({ connection, run }) => {
    console.log(connection, run?.status);
  });
  try {
    await watch.connect();
  } catch (error) {
    unsubscribe();
    await watch.dispose();
    throw error;
  }
  return async () => {
    unsubscribe();
    await watch.dispose();
  };
}

Call the returned cleanup function when the component or request scope ends. Reconnection resumes observation; it does not trigger a second run. Keep credentials on the server-side boundary for private jobs.

Cancel and retry are explicit controls with { runId, operationId }, allowing audit and recovery. The server may process them asynchronously; read or watch until the requested state appears.

Reference and source