Improve workflow metrics with faillure reason (#18768)
- split workflow errors into system and user errors - add workspace id to attributes for debugging
This commit is contained in:
+3
-2
@@ -62,14 +62,14 @@ export class ResumeDelayedWorkflowJob {
|
||||
if (!step || !isWorkflowDelayAction(step)) {
|
||||
throw new WorkflowRunException(
|
||||
'Step not found or is not a delay action',
|
||||
WorkflowRunExceptionCode.INVALID_INPUT,
|
||||
WorkflowRunExceptionCode.INVALID_OPERATION,
|
||||
);
|
||||
}
|
||||
|
||||
if (stepInfo?.status !== StepStatus.PENDING) {
|
||||
throw new WorkflowRunException(
|
||||
'Step is not pending',
|
||||
WorkflowRunExceptionCode.INVALID_INPUT,
|
||||
WorkflowRunExceptionCode.INVALID_OPERATION,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ export class ResumeDelayedWorkflowJob {
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: `Error during delay resume: ${String(error)}`,
|
||||
isSystemError: true,
|
||||
});
|
||||
|
||||
throw error;
|
||||
|
||||
+12
-2
@@ -9,6 +9,10 @@ import { HttpTool } from 'src/engine/core-modules/tool/tools/http-tool/http-tool
|
||||
import { SendEmailTool } from 'src/engine/core-modules/tool/tools/email-tool/send-email-tool';
|
||||
import { type ToolInput } from 'src/engine/core-modules/tool/types/tool-input.type';
|
||||
import { type Tool } from 'src/engine/core-modules/tool/types/tool.type';
|
||||
import {
|
||||
WorkflowStepExecutorException,
|
||||
WorkflowStepExecutorExceptionCode,
|
||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
||||
import { type WorkflowActionInput } from 'src/modules/workflow/workflow-executor/types/workflow-action-input';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import { type WorkflowSendEmailActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type';
|
||||
@@ -39,13 +43,19 @@ export class ToolExecutorWorkflowAction implements WorkflowAction {
|
||||
const step = steps.find((step) => step.id === currentStepId);
|
||||
|
||||
if (!step) {
|
||||
throw new Error('Step not found');
|
||||
throw new WorkflowStepExecutorException(
|
||||
'Step not found',
|
||||
WorkflowStepExecutorExceptionCode.STEP_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const tool = this.toolsByActionType.get(step.type);
|
||||
|
||||
if (!tool) {
|
||||
throw new Error(`No tool found for workflow action type: ${step.type}`);
|
||||
throw new WorkflowStepExecutorException(
|
||||
`No tool found for workflow action type: ${step.type}`,
|
||||
WorkflowStepExecutorExceptionCode.INVALID_STEP_TYPE,
|
||||
);
|
||||
}
|
||||
|
||||
let toolInput = step.settings.input;
|
||||
|
||||
+2
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { MetricsModule } from 'src/engine/core-modules/metrics/metrics.module';
|
||||
import { ToolModule } from 'src/engine/core-modules/tool/tool.module';
|
||||
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
||||
@@ -36,6 +37,7 @@ import { WorkflowRunModule } from 'src/modules/workflow/workflow-runner/workflow
|
||||
EmptyActionModule,
|
||||
FeatureFlagModule,
|
||||
ToolModule,
|
||||
MetricsModule,
|
||||
],
|
||||
providers: [
|
||||
WorkflowExecutorWorkspaceService,
|
||||
|
||||
+10
-1
@@ -6,7 +6,9 @@ import { BILLING_FEATURE_USED } from 'src/engine/core-modules/billing/constants/
|
||||
import { BILLING_WORKFLOW_EXECUTION_ERROR_MESSAGE } from 'src/engine/core-modules/billing/constants/billing-workflow-execution-error-message.constant';
|
||||
import { BillingMeterEventName } from 'src/engine/core-modules/billing/enums/billing-meter-event-names';
|
||||
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
|
||||
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
|
||||
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
||||
import { shouldExecuteStep } from 'src/modules/workflow/workflow-executor/utils/should-execute-step.util';
|
||||
@@ -14,7 +16,6 @@ import {
|
||||
type WorkflowAction,
|
||||
WorkflowActionType,
|
||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service';
|
||||
import { WorkflowRunWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service';
|
||||
|
||||
@@ -61,6 +62,10 @@ describe('WorkflowExecutorWorkspaceService', () => {
|
||||
captureExceptions: jest.fn(),
|
||||
};
|
||||
|
||||
const mockMetricsService = {
|
||||
incrementCounter: jest.fn(),
|
||||
};
|
||||
|
||||
const mockMessageQueueService = {
|
||||
add: jest.fn(),
|
||||
};
|
||||
@@ -97,6 +102,10 @@ describe('WorkflowExecutorWorkspaceService', () => {
|
||||
provide: `MESSAGE_QUEUE_${MessageQueue.workflowQueue}`,
|
||||
useValue: mockMessageQueueService,
|
||||
},
|
||||
{
|
||||
provide: MetricsService,
|
||||
useValue: mockMetricsService,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
+12
-2
@@ -19,6 +19,8 @@ import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handl
|
||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
|
||||
import { MetricsKeys } from 'src/engine/core-modules/metrics/types/metrics-keys.type';
|
||||
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
|
||||
import { WorkflowRunStatus } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||
import { workflowHasRunningSteps } from 'src/modules/workflow/common/utils/workflow-has-running-steps.util';
|
||||
@@ -57,6 +59,7 @@ export class WorkflowExecutorWorkspaceService {
|
||||
private readonly workflowRunWorkspaceService: WorkflowRunWorkspaceService,
|
||||
private readonly billingService: BillingService,
|
||||
private readonly exceptionHandlerService: ExceptionHandlerService,
|
||||
private readonly metricsService: MetricsService,
|
||||
@InjectMessageQueue(MessageQueue.workflowQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
) {}
|
||||
@@ -70,7 +73,7 @@ export class WorkflowExecutorWorkspaceService {
|
||||
}: WorkflowExecutorInput) {
|
||||
await Promise.all(
|
||||
stepIds.map(async (stepIdToExecute) => {
|
||||
await this.executeFromStep({
|
||||
return this.executeFromStep({
|
||||
stepId: stepIdToExecute,
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
@@ -92,7 +95,7 @@ export class WorkflowExecutorWorkspaceService {
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
executedStepsCount,
|
||||
}: WorkflowBranchExecutorInput) {
|
||||
}: WorkflowBranchExecutorInput): Promise<void> {
|
||||
const workflowRun =
|
||||
await this.workflowRunWorkspaceService.getWorkflowRunOrFail({
|
||||
workflowRunId,
|
||||
@@ -111,6 +114,7 @@ export class WorkflowExecutorWorkspaceService {
|
||||
workspaceId,
|
||||
status: WorkflowRunStatus.FAILED,
|
||||
error: 'Step not found',
|
||||
isSystemError: true,
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -500,6 +504,12 @@ export class WorkflowExecutorWorkspaceService {
|
||||
this.exceptionHandlerService.captureExceptions([error], {
|
||||
workspace: { id: workspaceId },
|
||||
});
|
||||
|
||||
await this.metricsService.incrementCounter({
|
||||
key: MetricsKeys.WorkflowRunSystemError,
|
||||
eventId: workflowRunId,
|
||||
debugLog: `[Workflow Run System Error] Workflow run ${workflowRunId} in workspace ${workspaceId} ended with system error`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user