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
70 changes: 69 additions & 1 deletion worker/src/temporal/__tests__/workflow-runner.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { beforeAll, describe, expect, it } from 'bun:test';
import { beforeAll, describe, expect, it, vi } from 'bun:test';
import { z } from 'zod';
import {
componentRegistry,
Expand Down Expand Up @@ -40,6 +40,74 @@ describe('executeWorkflow', () => {

componentRegistry.register(component);
}

if (!componentRegistry.has('test.silent.echo')) {
const component: ComponentDefinition = {
id: 'test.silent.echo',
label: 'Test Silent Echo',
category: 'transform',
runner: { kind: 'inline' },
inputs: inputs({
value: withPortMeta(z.string(), { label: 'Value' }),
}),
outputs: outputs({
echoed: withPortMeta(z.string(), { label: 'Echoed' }),
}),
async execute({ inputs }) {
return { echoed: inputs.value };
},
};

componentRegistry.register(component);
}
});

it('does not write workflow diagnostics to console.log by default', async () => {
const previousDebugFlag = process.env.SENTRIS_DEBUG_WORKFLOW;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});

try {
delete process.env.SENTRIS_DEBUG_WORKFLOW;

const definition: WorkflowDefinition = {
version: 1,
title: 'Quiet workflow diagnostics',
entrypoint: { ref: 'node-1' },
config: {
environment: 'test',
timeoutSeconds: 30,
},
nodes: {
'node-1': { ref: 'node-1' },
},
edges: [],
dependencyCounts: {
'node-1': 0,
},
actions: [
{
ref: 'node-1',
componentId: 'test.silent.echo',
params: {},
inputOverrides: { value: 'quiet' },
dependsOn: [],
inputMappings: {},
},
],
};

const result = await executeWorkflow(definition, {}, { runId: 'quiet-diagnostics' });

expect(result.success).toBe(true);
expect(logSpy).not.toHaveBeenCalled();
} finally {
if (previousDebugFlag === undefined) {
delete process.env.SENTRIS_DEBUG_WORKFLOW;
} else {
process.env.SENTRIS_DEBUG_WORKFLOW = previousDebugFlag;
}
logSpy.mockRestore();
}
});

it('records trace events with explicit levels in order of execution', async () => {
Expand Down
29 changes: 17 additions & 12 deletions worker/src/temporal/activities/run-workflow.activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
import type { IFileStorageService, ITraceService, ISecretsService } from '@sentris/component-sdk';
import type { ArtifactServiceFactory } from '../artifact-factory';
import { isTraceMetadataAware } from '../utils/trace-metadata';
import { workflowDiagnosticLog } from '../workflow-diagnostics';

interface WorkflowActivityServices {
storage: IFileStorageService;
Expand Down Expand Up @@ -48,14 +49,18 @@ function getWorkflowServices(): WorkflowActivityServices {
export async function runWorkflowActivity(
input: RunWorkflowActivityInput,
): Promise<RunWorkflowActivityOutput> {
console.log(`╔══════════════════════════════════════════════════════════════════════════════╗`);
console.log(`🔧 [ACTIVITY START] runWorkflowActivity called`);
console.log(`📋 Run ID: ${input.runId}`);
console.log(`📋 Workflow ID: ${input.workflowId}`);
console.log(`📋 Actions count: ${input.definition.actions.length}`);
console.log(`📋 Action refs: ${input.definition.actions.map((a) => a.ref).join(', ')}`);
console.log(`📋 Inputs keys: ${Object.keys(input.inputs || {}).join(', ')}`);
console.log(`╚══════════════════════════════════════════════════════════════════════════════╝`);
workflowDiagnosticLog(
`╔══════════════════════════════════════════════════════════════════════════════╗`,
);
workflowDiagnosticLog(`🔧 [ACTIVITY START] runWorkflowActivity called`);
workflowDiagnosticLog(`📋 Run ID: ${input.runId}`);
workflowDiagnosticLog(`📋 Workflow ID: ${input.workflowId}`);
workflowDiagnosticLog(`📋 Actions count: ${input.definition.actions.length}`);
workflowDiagnosticLog(`📋 Action refs: ${input.definition.actions.map((a) => a.ref).join(', ')}`);
workflowDiagnosticLog(`📋 Inputs keys: ${Object.keys(input.inputs || {}).join(', ')}`);
workflowDiagnosticLog(
`╚══════════════════════════════════════════════════════════════════════════════╝`,
);
const startTime = Date.now();

const svc = getWorkflowServices();
Expand All @@ -68,7 +73,7 @@ export async function runWorkflowActivity(
});
}

console.log(`⏳ [ACTIVITY] About to call executeWorkflow for ${input.runId}`);
workflowDiagnosticLog(`⏳ [ACTIVITY] About to call executeWorkflow for ${input.runId}`);
const result = await executeWorkflow(
input.definition,
{
Expand All @@ -88,10 +93,10 @@ export async function runWorkflowActivity(
},
);
const duration = Date.now() - startTime;
console.log(
workflowDiagnosticLog(
`✅ [ACTIVITY DONE] runWorkflow completed for run: ${input.runId} in ${duration}ms`,
);
console.log(`📊 [ACTIVITY] Result keys: ${Object.keys(result || {}).join(', ')}`);
workflowDiagnosticLog(`📊 [ACTIVITY] Result keys: ${Object.keys(result || {}).join(', ')}`);
return result;
} catch (error: unknown) {
const duration = Date.now() - startTime;
Expand All @@ -110,7 +115,7 @@ export async function runWorkflowActivity(
throw error;
} finally {
if (isTraceMetadataAware(svc.trace) && typeof svc.trace.finalizeRun === 'function') {
console.log(`🧹 [ACTIVITY] Finalizing trace metadata for ${input.runId}`);
workflowDiagnosticLog(`🧹 [ACTIVITY] Finalizing trace metadata for ${input.runId}`);
svc.trace.finalizeRun(input.runId);
}
}
Expand Down
9 changes: 9 additions & 0 deletions worker/src/temporal/workflow-diagnostics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function shouldLogWorkflowDiagnostics(): boolean {
return process.env.SENTRIS_DEBUG_WORKFLOW === '1';
}

export function workflowDiagnosticLog(...args: Parameters<typeof console.log>): void {
if (shouldLogWorkflowDiagnostics()) {
console.log(...args);
}
}
29 changes: 16 additions & 13 deletions worker/src/temporal/workflow-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { createLightweightSummary } from './utils/component-output';
import { buildActionPayload } from './input-resolver';
import { isComponentFailure, extractFailureMessage } from './workflows/workflow-helpers';
import type { ArtifactServiceFactory } from './artifact-factory';
import { workflowDiagnosticLog } from './workflow-diagnostics';

export interface ExecuteWorkflowOptions {
runId?: string;
Expand All @@ -52,9 +53,9 @@ export async function executeWorkflow(
options: ExecuteWorkflowOptions = {},
): Promise<WorkflowRunResult> {
const runId = options.runId ?? randomUUID();
console.log(`🏃 [WORKFLOW RUNNER] executeWorkflow called for runId: ${runId}`);
console.log(`📋 [WORKFLOW RUNNER] Definition has ${definition.actions.length} actions`);
console.log(`📋 [WORKFLOW RUNNER] Entrypoint ref: ${definition.entrypoint.ref}`);
workflowDiagnosticLog(`🏃 [WORKFLOW RUNNER] executeWorkflow called for runId: ${runId}`);
workflowDiagnosticLog(`📋 [WORKFLOW RUNNER] Definition has ${definition.actions.length} actions`);
workflowDiagnosticLog(`📋 [WORKFLOW RUNNER] Entrypoint ref: ${definition.entrypoint.ref}`);

const results = new Map<string, unknown>();
const actionsByRef = new Map<string, (typeof definition.actions)[number]>(
Expand Down Expand Up @@ -85,7 +86,7 @@ export async function executeWorkflow(
actionRef: string,
schedulerContext: WorkflowSchedulerRunContext,
): Promise<{ activePorts?: string[] | undefined } | null> => {
console.log(
workflowDiagnosticLog(
`🎯 [WORKFLOW RUNNER] runAction called for: ${actionRef} (triggered by: ${schedulerContext.triggeredBy || 'root'})`,
);

Expand Down Expand Up @@ -242,7 +243,7 @@ export async function executeWorkflow(
if (isEntrypointRef && request.inputs) {
// Only apply inputs to the actual entrypoint component, not just any node matching the entrypoint ref
if (isEntrypointComponent) {
console.log(
workflowDiagnosticLog(
`[WorkflowRunner] Applying inputs to entrypoint component '${action.ref}' (${action.componentId})`,
);
inputs.__runtimeData = request.inputs;
Expand Down Expand Up @@ -311,14 +312,14 @@ export async function executeWorkflow(
});

try {
console.log(
workflowDiagnosticLog(
`⚡️ [WORKFLOW RUNNER] Executing component: ${action.componentId} for action: ${actionRef}`,
);
const rawOutput = await component.execute(
{ inputs: parsedInputs, params: parsedParams },
context,
);
console.log(
workflowDiagnosticLog(
`✅ [WORKFLOW RUNNER] Component execution completed: ${action.componentId} for action: ${actionRef}`,
);
let output = component.outputs.parse(rawOutput);
Expand Down Expand Up @@ -351,7 +352,7 @@ export async function executeWorkflow(
}
}
results.set(action.ref, output);
console.log(`💾 [WORKFLOW RUNNER] Result stored for: ${actionRef}`);
workflowDiagnosticLog(`💾 [WORKFLOW RUNNER] Result stored for: ${actionRef}`);
// Record node I/O completion
await options.nodeIO?.recordCompletion({
runId,
Expand Down Expand Up @@ -460,8 +461,8 @@ export async function executeWorkflow(
run: runAction,
});

console.log(`📊 [WORKFLOW RUNNER] runWorkflowWithScheduler completed for ${runId}`);
console.log(`📊 [WORKFLOW RUNNER] Total results stored: ${results.size}`);
workflowDiagnosticLog(`📊 [WORKFLOW RUNNER] runWorkflowWithScheduler completed for ${runId}`);
workflowDiagnosticLog(`📊 [WORKFLOW RUNNER] Total results stored: ${results.size}`);

const outputsObject: Record<string, unknown> = {};
let reportedFailure = false;
Expand All @@ -476,8 +477,10 @@ export async function executeWorkflow(
}
});

console.log(`📊 [WORKFLOW RUNNER] Output keys: ${Object.keys(outputsObject).join(', ')}`);
console.log(`📊 [WORKFLOW RUNNER] Reported failure: ${reportedFailure}`);
workflowDiagnosticLog(
`📊 [WORKFLOW RUNNER] Output keys: ${Object.keys(outputsObject).join(', ')}`,
);
workflowDiagnosticLog(`📊 [WORKFLOW RUNNER] Reported failure: ${reportedFailure}`);

if (reportedFailure) {
const baseMessage = 'One or more workflow actions failed';
Expand All @@ -492,7 +495,7 @@ export async function executeWorkflow(
};
}

console.log(`✅ [WORKFLOW RUNNER] Workflow completed successfully for ${runId}`);
workflowDiagnosticLog(`✅ [WORKFLOW RUNNER] Workflow completed successfully for ${runId}`);
return { outputs: outputsObject, success: true };
} catch (error: unknown) {
console.error(`❌ [WORKFLOW RUNNER] Workflow threw exception for ${runId}:`, error);
Expand Down
Loading