Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions apps/hub/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ const HubEnv = type({
"SIGNIN_RATE_LIMIT_MAX?": type(/^[1-9]\d*$/).describe(
"the maximum failed sign-in attempts a single account may accrue per window before further failures are rejected, e.g. 10 — keyed on the target email, not client IP (see sign-in-rate-limit.ts); a correct password always succeeds regardless of this budget",
),
"ROUTINE_SCHEDULER_POLL_INTERVAL_MS?": type(/^[1-9]\d*$/).describe(
"dev/test-only override for the routine scheduler's poll interval, in milliseconds — unset (default) runs the real 30s production cadence; the e2e harness sets this to a fast interval so a scheduled-routine test doesn't wait out the real cadence",
),
"GOOGLE_CLIENT_ID?": type("string > 0").describe(
"Google OAuth client id; set together with GOOGLE_CLIENT_SECRET to enable Google sign-in",
),
Expand Down Expand Up @@ -282,10 +279,6 @@ export type HubConfig = {
readonly allowPlaintextSecrets: boolean;
/** Opt-in to initialize git-on-disk state inside an existing git work tree. */
readonly allowGitInsideWorkTree?: boolean;
/** Dev/test-only override for the routine scheduler's poll interval —
* see `ROUTINE_SCHEDULER_POLL_INTERVAL_MS` above. Unset runs the real
* production cadence (`routine-scheduler.ts`'s own default). */
readonly routineSchedulerPollIntervalMs?: number;
/** Every sidecar-allocation backend registered for exclusive placement,
* one or more, each addressable by its provisioner id. Never empty: an
* install that configures nothing registers the `process` backend, so
Expand Down Expand Up @@ -551,10 +544,6 @@ export function readHubConfig(
if (parsed.HUB_ALLOW_GIT_INSIDE_WORK_TREE !== undefined)
hubConfig.allowGitInsideWorkTree = true;
if (parsed.PORT !== undefined) hubConfig.listenPort = Number(parsed.PORT);
if (parsed.ROUTINE_SCHEDULER_POLL_INTERVAL_MS !== undefined)
hubConfig.routineSchedulerPollIntervalMs = Number(
parsed.ROUTINE_SCHEDULER_POLL_INTERVAL_MS,
);
if (parsed.HUGGINGFACE_OAUTH_CLIENT_ID !== undefined)
hubConfig.huggingfaceOAuthClientId = parsed.HUGGINGFACE_OAUTH_CLIENT_ID;
if (parsed.GITHUB_APP_CLIENT_ID !== undefined)
Expand Down
6 changes: 0 additions & 6 deletions apps/hub/src/cron-due.ts

This file was deleted.

12 changes: 6 additions & 6 deletions apps/hub/src/hub-zero-t4-registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// from the legacy template package.
//
// Part A (structural): `index.ts`, `pinned-package-credential-bindings.ts`,
// and `workflow-scheduler.ts` carry no legacy template import, and the
// and `native-workflow-routine-launch.ts` carry no legacy template import, and the
// delivery join (settings-row read + run-participant join) is gone —
// scheduled runs launch without joining a chat.
//
Expand Down Expand Up @@ -43,7 +43,7 @@ describe("hub-zero T4: no legacy template import in the hub", () => {
for (const rel of [
"index.ts",
"pinned-package-credential-bindings.ts",
"workflow-scheduler.ts",
"native-workflow-routine-launch.ts",
]) {
test(`${rel} imports no legacy template package`, () => {
expect(
Expand All @@ -56,20 +56,20 @@ describe("hub-zero T4: no legacy template import in the hub", () => {

describe("hub-zero T4: the scheduled delivery join is cut", () => {
test("no settings-row list read survives in the hub", () => {
for (const rel of ["index.ts", "workflow-scheduler.ts"]) {
for (const rel of ["index.ts", "native-workflow-routine-launch.ts"]) {
expect(
readHub(rel).includes(LIST_SETTINGS),
`${rel} still reads ${LIST_SETTINGS}`,
).toBe(false);
}
});

test("no delivery-join seam survives in workflow-scheduler.ts", () => {
const source = readHub("workflow-scheduler.ts");
test("no delivery-join seam survives in the routine launch path", () => {
const source = readHub("native-workflow-routine-launch.ts");
for (const needle of [JOIN_DEPS, JOIN_FN, JOIN_PORT, JOIN_INPUT]) {
expect(
source.includes(needle),
`workflow-scheduler.ts still contains ${needle}`,
`native-workflow-routine-launch.ts still contains ${needle}`,
).toBe(false);
}
});
Expand Down
27 changes: 1 addition & 26 deletions apps/hub/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,7 @@ import {
import type { SidecarProvisioner } from "@intx/hub-sessions";
import { withTurnPartWriteDefaults } from "./turn-part-content-default";
import { createBootAssetWiring, REGISTRIES } from "./asset-service-factory";
import {
claimScheduleMinuteFromDb,
createWorkflowScheduler,
launchScheduledDefinitionFromDb,
listScheduledDefinitionsFromDb,
runNowScheduledDefinition,
} from "./workflow-scheduler";
import { runNowScheduledDefinition } from "./native-workflow-routine-launch";
import { createToolGrantsForPins } from "./tool-grants";
import { drainHubServer, shutdownHub } from "./shutdown";
import {
Expand Down Expand Up @@ -2353,24 +2347,6 @@ export async function createHub(config: HubConfig) {
bus: mailboxBus,
});

// Recurring auto-fire: `workflow-scheduler.ts` ticks authored, deployed
// definitions whose frozen projection carries a native ScheduleTrigger.
// This hub has no general job-runner today, so the loop is scoped to
// exactly that job rather than standing up a bespoke cron daemon as a
// hidden dependency. Every hub replica can safely run it: each native
// fire is claimed on `workflow_definition.schedule_claimed_minute`.
const workflowScheduler = createWorkflowScheduler({
listScheduledDefinitions: listScheduledDefinitionsFromDb(db),
claimScheduleMinute: claimScheduleMinuteFromDb(db),
launch: launchScheduledDefinitionFromDb({
db,
sidecarRouter,
}),
...(config.routineSchedulerPollIntervalMs !== undefined
? { pollIntervalMs: config.routineSchedulerPollIntervalMs }
: {}),
});

app.get("/*", createStaticHandler(path.resolve(config.hubStaticDir)));

// Stock Interchange currently leaves tenant creation and dispatch ungated.
Expand Down Expand Up @@ -2402,7 +2378,6 @@ export async function createHub(config: HubConfig) {
relaunchSweepSeries += 1;
clearTimeout(relaunchSweepTimer);
chatOrchestrator.dispose();
workflowScheduler.stop();
credentialExpirySweep.stop();
inboxUnsnoozeSweep.stop();
await insightsUsage.close();
Expand Down
29 changes: 29 additions & 0 deletions apps/hub/src/native-workflow-routine-launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,32 @@ export async function triggerNativeWorkflowRoutineRun(

return { runId: anchor.id, address };
}

export type RunNowScheduledDefinitionArgs = {
tenantId: string;
definitionId: string;
principalId: string;
fromDomain: string;
content: string;
name: string;
definitionAssetId: string;
};

/**
* Fire a schedule-triggered definition now and return its `{ runId }`. No
* delivery join: the run launches straight into the runner (hub-zero T4,
* CL-8126).
*/
export async function runNowScheduledDefinition(
deps: NativeWorkflowRoutineTriggerDeps,
args: RunNowScheduledDefinitionArgs,
): Promise<{ runId: string }> {
const triggered = await triggerNativeWorkflowRoutineRun(deps, {
tenantId: args.tenantId,
definitionId: args.definitionId,
principalId: args.principalId,
fromDomain: args.fromDomain,
content: args.content,
});
return { runId: triggered.runId };
}
Loading
Loading