Skip to content

Operations

Two features for background work and operator-controlled feature gates.

Jobs: cron, event and manual background work with run history

Status: ✅ Stable

What: Persistence and operator tooling for jobs registered with r.job(...). Built on BullMQ + Redis with lane routing (runIn: "api" | "worker"). Every run is written to store_job_runs / store_job_run_logs.

How it works: r.job(name, { trigger, runIn?, … }, handler) registers a worker. Handler signature is (payload, context), not (ctx) alone.

TriggerHow it fires
{ manual: true }jobs:write:trigger (operator / SystemAdmin) or JobRunner.dispatch(name, payload)
{ cron: "0 9 * * *" }Leader-elected schedule
{ on: writeHandlerOrEvent }After the named write/event

There is no ctx.jobs.enqueue. Manual runs go through the trigger write handler or the job runner.

Example:

import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
defineFeature("ops", (r) => {
r.job(
"cleanup-old-attempts",
{ trigger: { cron: "0 3 * * *" }, runIn: "worker" },
async (_payload, ctx) => {
// use ctx.db / ctx.notify / …, payload first, context second
},
);
r.job(
"send-incident-email",
{ trigger: { manual: true } },
async (payload, ctx) => {
await ctx.notify!("incident-email", {
to: payload["recipientId"] as string,
data: { incidentId: payload["incidentId"] },
});
},
);
});
// Trigger a manual job (SystemAdmin), not ctx.jobs.enqueue
await ctx.write("jobs:write:trigger", {
jobName: "ops:job:send-incident-email", // qualified name as registered
payload: { incidentId: id, recipientId },
});

Status: ✅ Stable

What: Global (not per-tenant) enable/disable for features that opt in with r.toggleable({ default }). Operators flip state via feature-toggles:write:set; the dispatcher gates disabled features (feature_disabled). State lives in store_global_feature_state.

How it works: Declare r.toggleable({ default: false }) once on the feature. There is no ctx.toggles, when a feature is off, its handlers are unreachable and cross-feature hooks owned by that feature are skipped. Load createFeatureTogglesFeature({ getRuntime }) and wire GlobalFeatureToggleRuntime into the server’s effectiveFeatures callback (see the recipe).

Best practice: when a toggle is fully rolled out, delete it from code. In tests set toggle state explicitly.

Recipe: samples/recipes/feature-toggles

Example:

import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
import { z } from "zod";
export const billingFeature = defineFeature("billing", (r) => {
r.toggleable({ default: false });
// When "billing" is globally off, this handler never runs :
// the dispatcher returns feature_disabled. No ctx.toggles check.
r.queryHandler(
"invoice-list",
z.object({}),
async (_query, ctx) => {
/* list invoices */
},
{ access: { roles: ["Admin"] } },
);
});