@gadmin2n/schematics 0.0.152 → 0.0.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/application/files/gadmin2-game-angle-demo/.git-blame-ignore-revs +5 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/.nvmrc +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.local.md +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.md +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.codegen +16 -9
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.server +21 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.web +11 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/Jenkinsfile +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/PRODUCT.md +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/compose-ctl.sh +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.yml +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/readme.md +22 -22
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.oxfmtrc.json +13 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.oxlintrc.json +17 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.seed-timestamp +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +14 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/pnpm-workspace.yaml +23 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +2 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permission.seed.ts +23 -44
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +25 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +74 -64
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/auth.guard.ts +4 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/tracing.ts +4 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.service.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.ts +6 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.ts +6 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.ts +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.ts +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/page-transfer.service.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.service.spec.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.errors.ts +4 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.registry.ts +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.types.ts +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/parameter-binding.ts +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +0 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +17 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +58 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +66 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.ts +5 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +61 -149
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution.dto.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.spec.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.spec.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.spec.ts +38 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +18 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.dto.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +142 -253
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.ts +3 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/start-prod.sh +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/.oxfmtrc.json +12 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/.oxlintrc.json +24 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/README.MD +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/nginx.conf +0 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +17 -17
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/pnpm-workspace.yaml +13 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/VanillaJSONEditor/index.jsx +4 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/propPatcher.ts +36 -8
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.test.ts +7 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +6 -36
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/style.css +24 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +0 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +29 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +29 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/components/action-cell.css +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/index.tsx +20 -17
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/index.tsx +38 -35
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/detail.tsx +6 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/index.tsx +24 -22
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/EnhancedFlowRenderer.tsx +0 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/StatusCards.tsx +24 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.tsx +20 -18
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +7 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +28 -79
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instances.tsx +5 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/NodeInstanceForm.tsx +0 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +227 -97
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +62 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/settings/index.tsx +73 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +21 -46
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/index.css +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/test/setup.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/vite.config.ts +53 -41
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/vitest.config.ts +8 -2
- package/package.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.eslintrc.js +0 -28
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.prettierignore +0 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.prettierrc +0 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/.eslintrc.json +0 -38
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/.prettierignore +0 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/.prettierrc +0 -4
|
@@ -19,11 +19,7 @@ import {
|
|
|
19
19
|
scopedIdempotencyKey,
|
|
20
20
|
workflowDataHash,
|
|
21
21
|
} from './manual-workflow-execution';
|
|
22
|
-
import {
|
|
23
|
-
TemporalService,
|
|
24
|
-
WorkflowRetryCheckpoint,
|
|
25
|
-
workflowTemporalId,
|
|
26
|
-
} from './temporal.service';
|
|
22
|
+
import { TemporalService, workflowTemporalId } from './temporal.service';
|
|
27
23
|
import { verifyWebhookSignature } from './webhook-signature.util';
|
|
28
24
|
import { describeCallableWorkflow } from './workflow-callable';
|
|
29
25
|
import { WorkflowCompilerService } from './workflow-compiler.service';
|
|
@@ -97,19 +93,22 @@ type CronSchedulePlan =
|
|
|
97
93
|
version: { id: bigint; dsl: unknown };
|
|
98
94
|
};
|
|
99
95
|
const WORKFLOW_PUBLISH_LOCK_KEY = BigInt(734_221_907);
|
|
100
|
-
const RETRYABLE_MAIN_FLOW_NODE_TYPES = new Set([
|
|
101
|
-
'http_request',
|
|
102
|
-
'db_execute',
|
|
103
|
-
'code',
|
|
104
|
-
'delay',
|
|
105
|
-
'sub_workflow',
|
|
106
|
-
]);
|
|
107
|
-
|
|
108
96
|
interface WorkflowExecutionInternalOptions {
|
|
109
97
|
operationScopeId?: string;
|
|
110
|
-
retryCheckpoint?: WorkflowRetryCheckpoint;
|
|
111
98
|
retryOfInstanceId?: bigint;
|
|
112
|
-
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type WorkflowServiceOutcome<T> =
|
|
102
|
+
| { kind: 'ok'; value: T }
|
|
103
|
+
| { kind: 'not_found'; message: string }
|
|
104
|
+
| { kind: 'conflict'; message: string }
|
|
105
|
+
| { kind: 'invalid_input'; message: string };
|
|
106
|
+
|
|
107
|
+
export interface WorkflowExecutionResult {
|
|
108
|
+
instanceId: string;
|
|
109
|
+
temporalRunId: string | null;
|
|
110
|
+
workflowVersionId: string;
|
|
111
|
+
status: string;
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
function dslUsesBusinessEvent(dsl: unknown, registrationCode: string): boolean {
|
|
@@ -325,8 +324,8 @@ function validateBusinessEventMatch(
|
|
|
325
324
|
field.type === 'number'
|
|
326
325
|
? 'NUMBER'
|
|
327
326
|
: field.type === 'boolean'
|
|
328
|
-
|
|
329
|
-
|
|
327
|
+
? 'BOOLEAN'
|
|
328
|
+
: 'STRING';
|
|
330
329
|
let values: unknown[] = [right.value];
|
|
331
330
|
if (operator === 'IN') {
|
|
332
331
|
try {
|
|
@@ -564,7 +563,7 @@ export class WorkflowService {
|
|
|
564
563
|
const latest = workflow.versions?.[0]?.dsl;
|
|
565
564
|
return Boolean(
|
|
566
565
|
workflow.dsl &&
|
|
567
|
-
|
|
566
|
+
(!latest || !areWorkflowDslSourcesEqual(workflow.dsl, latest)),
|
|
568
567
|
);
|
|
569
568
|
}
|
|
570
569
|
|
|
@@ -644,6 +643,7 @@ export class WorkflowService {
|
|
|
644
643
|
{
|
|
645
644
|
pending: number;
|
|
646
645
|
running: number;
|
|
646
|
+
waiting_retry: number;
|
|
647
647
|
completed: number;
|
|
648
648
|
failed: number;
|
|
649
649
|
cancelled: number;
|
|
@@ -654,6 +654,7 @@ export class WorkflowService {
|
|
|
654
654
|
runsMap.set(row.workflowId, {
|
|
655
655
|
pending: 0,
|
|
656
656
|
running: 0,
|
|
657
|
+
waiting_retry: 0,
|
|
657
658
|
completed: 0,
|
|
658
659
|
failed: 0,
|
|
659
660
|
cancelled: 0,
|
|
@@ -681,6 +682,7 @@ export class WorkflowService {
|
|
|
681
682
|
runs: runsMap.get(item.id) || {
|
|
682
683
|
pending: 0,
|
|
683
684
|
running: 0,
|
|
685
|
+
waiting_retry: 0,
|
|
684
686
|
completed: 0,
|
|
685
687
|
failed: 0,
|
|
686
688
|
cancelled: 0,
|
|
@@ -752,7 +754,7 @@ export class WorkflowService {
|
|
|
752
754
|
typeof dsl === 'object' &&
|
|
753
755
|
!Array.isArray(dsl) &&
|
|
754
756
|
Array.isArray((dsl as { nodes?: unknown }).nodes)
|
|
755
|
-
? (dsl as { nodes: Array<{ type?: string }> }).nodes ?? []
|
|
757
|
+
? ((dsl as { nodes: Array<{ type?: string }> }).nodes ?? [])
|
|
756
758
|
: [];
|
|
757
759
|
if (
|
|
758
760
|
nodes.filter((node) => node.type === 'webhook_trigger').length === 1
|
|
@@ -1407,7 +1409,7 @@ export class WorkflowService {
|
|
|
1407
1409
|
const activeInstances = await tx.workflowInstance.count({
|
|
1408
1410
|
where: {
|
|
1409
1411
|
workflowId,
|
|
1410
|
-
status: { in: ['PENDING', 'RUNNING'] },
|
|
1412
|
+
status: { in: ['PENDING', 'RUNNING', 'WAITING_RETRY'] },
|
|
1411
1413
|
},
|
|
1412
1414
|
});
|
|
1413
1415
|
if (activeInstances > 0)
|
|
@@ -1480,7 +1482,7 @@ export class WorkflowService {
|
|
|
1480
1482
|
const config =
|
|
1481
1483
|
override && typeof override === 'object' && !Array.isArray(override)
|
|
1482
1484
|
? asRecord(override)
|
|
1483
|
-
: instanceConfigs.get(instanceId) ?? asRecord(node.config);
|
|
1485
|
+
: (instanceConfigs.get(instanceId) ?? asRecord(node.config));
|
|
1484
1486
|
return String(config.workflowId ?? '') === String(workflowId);
|
|
1485
1487
|
});
|
|
1486
1488
|
};
|
|
@@ -1589,10 +1591,10 @@ export class WorkflowService {
|
|
|
1589
1591
|
nodeType.outputs === null
|
|
1590
1592
|
? null
|
|
1591
1593
|
: Array.isArray(nodeType.outputs)
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1594
|
+
? nodeType.outputs.filter(
|
|
1595
|
+
(output): output is string => typeof output === 'string',
|
|
1596
|
+
)
|
|
1597
|
+
: [],
|
|
1596
1598
|
]),
|
|
1597
1599
|
) as NodeOutputsMap;
|
|
1598
1600
|
const handleErrors = validateWorkflowHandles(
|
|
@@ -1727,19 +1729,24 @@ export class WorkflowService {
|
|
|
1727
1729
|
}
|
|
1728
1730
|
|
|
1729
1731
|
async getStats(workflowId: bigint) {
|
|
1730
|
-
const [running, failed, completed, total] = await Promise.all(
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1732
|
+
const [running, waitingRetry, failed, completed, total] = await Promise.all(
|
|
1733
|
+
[
|
|
1734
|
+
this.prisma.workflowInstance.count({
|
|
1735
|
+
where: { workflowId, status: 'RUNNING' },
|
|
1736
|
+
}),
|
|
1737
|
+
this.prisma.workflowInstance.count({
|
|
1738
|
+
where: { workflowId, status: 'WAITING_RETRY' },
|
|
1739
|
+
}),
|
|
1740
|
+
this.prisma.workflowInstance.count({
|
|
1741
|
+
where: { workflowId, status: 'FAILED' },
|
|
1742
|
+
}),
|
|
1743
|
+
this.prisma.workflowInstance.count({
|
|
1744
|
+
where: { workflowId, status: 'COMPLETED' },
|
|
1745
|
+
}),
|
|
1746
|
+
this.prisma.workflowInstance.count({ where: { workflowId } }),
|
|
1747
|
+
],
|
|
1748
|
+
);
|
|
1749
|
+
return { running, waitingRetry, failed, completed, total };
|
|
1743
1750
|
}
|
|
1744
1751
|
|
|
1745
1752
|
async getWorkflowStatsByCode(code: string) {
|
|
@@ -1764,6 +1771,7 @@ export class WorkflowService {
|
|
|
1764
1771
|
failed24h,
|
|
1765
1772
|
running,
|
|
1766
1773
|
pending,
|
|
1774
|
+
waitingRetry,
|
|
1767
1775
|
] = await Promise.all([
|
|
1768
1776
|
this.prisma.workflowInstance.count(),
|
|
1769
1777
|
this.prisma.workflowInstance.count({
|
|
@@ -1779,6 +1787,9 @@ export class WorkflowService {
|
|
|
1779
1787
|
}),
|
|
1780
1788
|
this.prisma.workflowInstance.count({ where: { status: 'RUNNING' } }),
|
|
1781
1789
|
this.prisma.workflowInstance.count({ where: { status: 'PENDING' } }),
|
|
1790
|
+
this.prisma.workflowInstance.count({
|
|
1791
|
+
where: { status: 'WAITING_RETRY' },
|
|
1792
|
+
}),
|
|
1782
1793
|
]);
|
|
1783
1794
|
|
|
1784
1795
|
// Success rate calculation
|
|
@@ -1828,6 +1839,7 @@ export class WorkflowService {
|
|
|
1828
1839
|
},
|
|
1829
1840
|
running,
|
|
1830
1841
|
pending,
|
|
1842
|
+
waitingRetry,
|
|
1831
1843
|
};
|
|
1832
1844
|
}
|
|
1833
1845
|
|
|
@@ -1902,7 +1914,6 @@ export class WorkflowService {
|
|
|
1902
1914
|
const executionContext = createWorkflowExecutionState(
|
|
1903
1915
|
dto.workflow,
|
|
1904
1916
|
internal?.operationScopeId,
|
|
1905
|
-
internal?.retryCheckpoint,
|
|
1906
1917
|
);
|
|
1907
1918
|
const idempotencyRequestHash = dto.idempotencyKey
|
|
1908
1919
|
? workflowDataHash(
|
|
@@ -1938,7 +1949,6 @@ export class WorkflowService {
|
|
|
1938
1949
|
}),
|
|
1939
1950
|
...(internal?.retryOfInstanceId && {
|
|
1940
1951
|
retryOfInstanceId: internal.retryOfInstanceId,
|
|
1941
|
-
retryFromNodeId: internal.retryFromNodeId,
|
|
1942
1952
|
}),
|
|
1943
1953
|
creator,
|
|
1944
1954
|
},
|
|
@@ -2011,7 +2021,6 @@ export class WorkflowService {
|
|
|
2011
2021
|
versionId: Number(instanceVersion.id),
|
|
2012
2022
|
dsl: instanceVersion.dsl,
|
|
2013
2023
|
context: instance.context as Record<string, any>,
|
|
2014
|
-
retryCheckpoint: readRetryCheckpoint(instance.context),
|
|
2015
2024
|
});
|
|
2016
2025
|
} catch (error) {
|
|
2017
2026
|
await this.workflowLifecycle.markFailed({
|
|
@@ -2250,7 +2259,6 @@ export class WorkflowService {
|
|
|
2250
2259
|
select: {
|
|
2251
2260
|
id: true,
|
|
2252
2261
|
status: true,
|
|
2253
|
-
retryFromNodeId: true,
|
|
2254
2262
|
createdAt: true,
|
|
2255
2263
|
},
|
|
2256
2264
|
}),
|
|
@@ -2271,16 +2279,10 @@ export class WorkflowService {
|
|
|
2271
2279
|
workflow: { name: instance.workflow.name },
|
|
2272
2280
|
approvableNodeIds: approvableRequests.map((request) => request.nodeId),
|
|
2273
2281
|
retryableNodeIds:
|
|
2274
|
-
instance.status === '
|
|
2275
|
-
?
|
|
2276
|
-
dsl,
|
|
2277
|
-
instance.nodeExecutions,
|
|
2278
|
-
readRetryCheckpoint(instance.context),
|
|
2279
|
-
)
|
|
2282
|
+
instance.status === 'WAITING_RETRY' && dsl
|
|
2283
|
+
? listSameRunRetryableNodeIds(dsl, instance.nodeExecutions)
|
|
2280
2284
|
: [],
|
|
2281
2285
|
retryAttempts,
|
|
2282
|
-
reusedNodeIds:
|
|
2283
|
-
readRetryCheckpoint(instance.context)?.completedNodeIds ?? [],
|
|
2284
2286
|
dsl,
|
|
2285
2287
|
};
|
|
2286
2288
|
}
|
|
@@ -2306,15 +2308,15 @@ export class WorkflowService {
|
|
|
2306
2308
|
...(Object.prototype.hasOwnProperty.call(result, 'output') && {
|
|
2307
2309
|
result: result.output,
|
|
2308
2310
|
}),
|
|
2309
|
-
...(instance.status
|
|
2311
|
+
...(['FAILED', 'WAITING_RETRY'].includes(instance.status) && {
|
|
2310
2312
|
error: {
|
|
2311
2313
|
...(typeof result.code === 'string' ? { code: result.code } : {}),
|
|
2312
2314
|
message:
|
|
2313
2315
|
typeof result.message === 'string'
|
|
2314
2316
|
? result.message
|
|
2315
2317
|
: typeof result.error === 'string'
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
+
? result.error
|
|
2319
|
+
: 'Workflow execution failed',
|
|
2318
2320
|
},
|
|
2319
2321
|
}),
|
|
2320
2322
|
};
|
|
@@ -2347,10 +2349,10 @@ export class WorkflowService {
|
|
|
2347
2349
|
if (!instance) throw new NotFoundException('Workflow instance not found');
|
|
2348
2350
|
if (
|
|
2349
2351
|
instance.status !== 'CANCELLED' &&
|
|
2350
|
-
!['RUNNING', 'PENDING'].includes(instance.status)
|
|
2352
|
+
!['RUNNING', 'PENDING', 'WAITING_RETRY'].includes(instance.status)
|
|
2351
2353
|
)
|
|
2352
2354
|
throw new ConflictException(
|
|
2353
|
-
'Only RUNNING or
|
|
2355
|
+
'Only RUNNING, PENDING, or WAITING_RETRY instances can be cancelled',
|
|
2354
2356
|
);
|
|
2355
2357
|
if (
|
|
2356
2358
|
instance.status !== 'CANCELLED' &&
|
|
@@ -2510,7 +2512,7 @@ export class WorkflowService {
|
|
|
2510
2512
|
|
|
2511
2513
|
const reservedInstances = await this.prisma.workflowInstance.findMany({
|
|
2512
2514
|
where: {
|
|
2513
|
-
status: { in: ['PENDING', 'RUNNING'] },
|
|
2515
|
+
status: { in: ['PENDING', 'RUNNING', 'WAITING_RETRY'] },
|
|
2514
2516
|
temporalRunId: { not: null },
|
|
2515
2517
|
updatedAt: { lte: cutoff },
|
|
2516
2518
|
},
|
|
@@ -2529,7 +2531,10 @@ export class WorkflowService {
|
|
|
2529
2531
|
instance.temporalRunId!,
|
|
2530
2532
|
);
|
|
2531
2533
|
if (temporalState.kind === 'MISSING') {
|
|
2532
|
-
if (
|
|
2534
|
+
if (
|
|
2535
|
+
instance.status === 'RUNNING' ||
|
|
2536
|
+
instance.status === 'WAITING_RETRY'
|
|
2537
|
+
) {
|
|
2533
2538
|
await this.failMissingRunningInstance(
|
|
2534
2539
|
instance.id,
|
|
2535
2540
|
instance.temporalRunId!,
|
|
@@ -2555,7 +2560,6 @@ export class WorkflowService {
|
|
|
2555
2560
|
versionId: Number(instance.versionId),
|
|
2556
2561
|
dsl: version.dsl,
|
|
2557
2562
|
context: (instance.context ?? {}) as Record<string, any>,
|
|
2558
|
-
retryCheckpoint: readRetryCheckpoint(instance.context),
|
|
2559
2563
|
});
|
|
2560
2564
|
} catch (error) {
|
|
2561
2565
|
await this.failUnstartedInstance(
|
|
@@ -2599,7 +2603,7 @@ export class WorkflowService {
|
|
|
2599
2603
|
): Promise<void> {
|
|
2600
2604
|
await this.workflowLifecycle.markFailed({
|
|
2601
2605
|
instanceId,
|
|
2602
|
-
expectedStatuses: ['RUNNING'],
|
|
2606
|
+
expectedStatuses: ['RUNNING', 'WAITING_RETRY'],
|
|
2603
2607
|
temporalRunId,
|
|
2604
2608
|
result: {
|
|
2605
2609
|
code: 'TEMPORAL_EXECUTION_MISSING',
|
|
@@ -2685,7 +2689,7 @@ export class WorkflowService {
|
|
|
2685
2689
|
if (state.status !== 'COMPLETED' && state.status !== 'CANCELLED') {
|
|
2686
2690
|
await this.workflowLifecycle.markFailed({
|
|
2687
2691
|
instanceId,
|
|
2688
|
-
expectedStatuses: ['PENDING', 'RUNNING'],
|
|
2692
|
+
expectedStatuses: ['PENDING', 'RUNNING', 'WAITING_RETRY'],
|
|
2689
2693
|
temporalRunId,
|
|
2690
2694
|
result:
|
|
2691
2695
|
state.result === undefined
|
|
@@ -2702,7 +2706,7 @@ export class WorkflowService {
|
|
|
2702
2706
|
await this.prisma.workflowInstance.updateMany({
|
|
2703
2707
|
where: {
|
|
2704
2708
|
id: instanceId,
|
|
2705
|
-
status: { in: ['PENDING', 'RUNNING'] },
|
|
2709
|
+
status: { in: ['PENDING', 'RUNNING', 'WAITING_RETRY'] },
|
|
2706
2710
|
temporalRunId,
|
|
2707
2711
|
},
|
|
2708
2712
|
data: {
|
|
@@ -2785,59 +2789,72 @@ export class WorkflowService {
|
|
|
2785
2789
|
);
|
|
2786
2790
|
}
|
|
2787
2791
|
|
|
2788
|
-
async
|
|
2792
|
+
async retryFailedNode(
|
|
2789
2793
|
instanceId: bigint,
|
|
2790
2794
|
nodeId: string,
|
|
2791
|
-
creator: string,
|
|
2792
2795
|
temporalService: TemporalService,
|
|
2793
|
-
) {
|
|
2796
|
+
): Promise<WorkflowServiceOutcome<WorkflowExecutionResult>> {
|
|
2794
2797
|
const instance = await this.prisma.workflowInstance.findUnique({
|
|
2795
2798
|
where: { id: instanceId },
|
|
2796
2799
|
include: { nodeExecutions: true },
|
|
2797
2800
|
});
|
|
2798
|
-
if (!instance)
|
|
2799
|
-
if (instance.status !== '
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
where: { retryOfInstanceId: instance.id },
|
|
2805
|
-
orderBy: { createdAt: 'desc' },
|
|
2806
|
-
});
|
|
2807
|
-
if (existingRetry) return workflowExecutionResult(existingRetry);
|
|
2801
|
+
if (!instance) return { kind: 'not_found', message: 'Instance not found' };
|
|
2802
|
+
if (instance.status !== 'WAITING_RETRY')
|
|
2803
|
+
return {
|
|
2804
|
+
kind: 'conflict',
|
|
2805
|
+
message: '只有等待重试的 Workflow 才能重试失败节点',
|
|
2806
|
+
};
|
|
2808
2807
|
|
|
2809
2808
|
const version = await this.prisma.workflowVersion.findUnique({
|
|
2810
2809
|
where: { id: instance.versionId },
|
|
2811
2810
|
select: { dsl: true },
|
|
2812
2811
|
});
|
|
2813
|
-
if (!version)
|
|
2812
|
+
if (!version)
|
|
2813
|
+
return { kind: 'not_found', message: 'Workflow version not found' };
|
|
2814
2814
|
|
|
2815
|
-
const
|
|
2815
|
+
const invalidTargetMessage = validateSameRunRetryTarget(
|
|
2816
2816
|
version.dsl,
|
|
2817
2817
|
instance.nodeExecutions,
|
|
2818
2818
|
nodeId,
|
|
2819
|
-
readRetryCheckpoint(instance.context),
|
|
2820
2819
|
);
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
},
|
|
2832
|
-
creator,
|
|
2833
|
-
temporalService,
|
|
2834
|
-
{
|
|
2835
|
-
operationScopeId: String(operationScopeId),
|
|
2836
|
-
retryCheckpoint,
|
|
2837
|
-
retryOfInstanceId: instance.id,
|
|
2838
|
-
retryFromNodeId: nodeId,
|
|
2839
|
-
},
|
|
2820
|
+
if (invalidTargetMessage)
|
|
2821
|
+
return { kind: 'invalid_input', message: invalidTargetMessage };
|
|
2822
|
+
if (!instance.temporalRunId)
|
|
2823
|
+
return {
|
|
2824
|
+
kind: 'conflict',
|
|
2825
|
+
message: '当前 Workflow 没有可继续的 Temporal Run',
|
|
2826
|
+
};
|
|
2827
|
+
const failedExecution = instance.nodeExecutions.find(
|
|
2828
|
+
(execution) =>
|
|
2829
|
+
execution.nodeId === nodeId && execution.status === 'FAILED',
|
|
2840
2830
|
);
|
|
2831
|
+
if (!failedExecution)
|
|
2832
|
+
return { kind: 'invalid_input', message: '只能重试当前失败的节点' };
|
|
2833
|
+
try {
|
|
2834
|
+
await temporalService.signalWorkflow(
|
|
2835
|
+
instance.temporalRunId,
|
|
2836
|
+
'retryNode',
|
|
2837
|
+
{
|
|
2838
|
+
nodeId,
|
|
2839
|
+
requestId: `retry-node:${
|
|
2840
|
+
instance.id
|
|
2841
|
+
}:${nodeId}:${failedExecution.updatedAt.toISOString()}`,
|
|
2842
|
+
},
|
|
2843
|
+
);
|
|
2844
|
+
} catch (error) {
|
|
2845
|
+
this.logger.error(
|
|
2846
|
+
`workflow_node_retry_signal_failed - instanceId: ${
|
|
2847
|
+
instance.id
|
|
2848
|
+
}, nodeId: ${nodeId}, error: ${
|
|
2849
|
+
error instanceof Error ? error.message : String(error)
|
|
2850
|
+
}`,
|
|
2851
|
+
);
|
|
2852
|
+
throw error;
|
|
2853
|
+
}
|
|
2854
|
+
this.logger.log(
|
|
2855
|
+
`workflow_node_retry_signal_sent - instanceId: ${instance.id}, nodeId: ${nodeId}`,
|
|
2856
|
+
);
|
|
2857
|
+
return { kind: 'ok', value: workflowExecutionResult(instance) };
|
|
2841
2858
|
}
|
|
2842
2859
|
|
|
2843
2860
|
async approveInstance(
|
|
@@ -2868,15 +2885,13 @@ export class WorkflowService {
|
|
|
2868
2885
|
function createWorkflowExecutionState(
|
|
2869
2886
|
value: Record<string, any> | undefined,
|
|
2870
2887
|
operationScopeId?: string,
|
|
2871
|
-
retryCheckpoint?: WorkflowRetryCheckpoint,
|
|
2872
2888
|
): Record<string, any> {
|
|
2873
2889
|
return {
|
|
2874
2890
|
workflow: value ?? {},
|
|
2875
2891
|
nodes: {},
|
|
2876
|
-
...(
|
|
2892
|
+
...(operationScopeId && {
|
|
2877
2893
|
system: {
|
|
2878
|
-
|
|
2879
|
-
...(retryCheckpoint && { retryCheckpoint }),
|
|
2894
|
+
operationScopeId,
|
|
2880
2895
|
},
|
|
2881
2896
|
}),
|
|
2882
2897
|
};
|
|
@@ -2887,7 +2902,7 @@ function workflowExecutionResult(instance: {
|
|
|
2887
2902
|
versionId: bigint;
|
|
2888
2903
|
status: string;
|
|
2889
2904
|
temporalRunId: string | null;
|
|
2890
|
-
}) {
|
|
2905
|
+
}): WorkflowExecutionResult {
|
|
2891
2906
|
return {
|
|
2892
2907
|
instanceId: instance.id.toString(),
|
|
2893
2908
|
temporalRunId: instance.temporalRunId,
|
|
@@ -2910,50 +2925,11 @@ function quoteLiteral(value: string): string {
|
|
|
2910
2925
|
return `'${value.replace(/'/g, "''")}'`;
|
|
2911
2926
|
}
|
|
2912
2927
|
|
|
2913
|
-
function
|
|
2914
|
-
value: unknown,
|
|
2915
|
-
): WorkflowRetryCheckpoint | undefined {
|
|
2916
|
-
const checkpoint = asRecord(asRecord(value).system).retryCheckpoint;
|
|
2917
|
-
if (
|
|
2918
|
-
!checkpoint ||
|
|
2919
|
-
typeof checkpoint !== 'object' ||
|
|
2920
|
-
Array.isArray(checkpoint)
|
|
2921
|
-
)
|
|
2922
|
-
return undefined;
|
|
2923
|
-
const record = checkpoint as Record<string, unknown>;
|
|
2924
|
-
if (
|
|
2925
|
-
typeof record.startNodeId !== 'string' ||
|
|
2926
|
-
!Array.isArray(record.completedNodeIds) ||
|
|
2927
|
-
!record.completedNodeIds.every((item) => typeof item === 'string') ||
|
|
2928
|
-
!record.outputs ||
|
|
2929
|
-
typeof record.outputs !== 'object' ||
|
|
2930
|
-
Array.isArray(record.outputs)
|
|
2931
|
-
)
|
|
2932
|
-
return undefined;
|
|
2933
|
-
const outputs = record.outputs as Record<string, unknown>;
|
|
2934
|
-
if (
|
|
2935
|
-
!record.completedNodeIds.every((nodeId) =>
|
|
2936
|
-
Object.prototype.hasOwnProperty.call(outputs, nodeId),
|
|
2937
|
-
)
|
|
2938
|
-
)
|
|
2939
|
-
return undefined;
|
|
2940
|
-
return {
|
|
2941
|
-
startNodeId: record.startNodeId,
|
|
2942
|
-
completedNodeIds: record.completedNodeIds,
|
|
2943
|
-
outputs,
|
|
2944
|
-
};
|
|
2945
|
-
}
|
|
2946
|
-
|
|
2947
|
-
function buildRetryCheckpoint(
|
|
2928
|
+
function validateSameRunRetryTarget(
|
|
2948
2929
|
dslValue: unknown,
|
|
2949
|
-
nodeExecutions: Array<{
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
output: unknown;
|
|
2953
|
-
}>,
|
|
2954
|
-
retryFromNodeId: string,
|
|
2955
|
-
inheritedCheckpoint?: WorkflowRetryCheckpoint,
|
|
2956
|
-
): WorkflowRetryCheckpoint {
|
|
2930
|
+
nodeExecutions: Array<{ nodeId: string; status: string }>,
|
|
2931
|
+
nodeId: string,
|
|
2932
|
+
): string | undefined {
|
|
2957
2933
|
const dsl = asRecord(dslValue);
|
|
2958
2934
|
const nodes = Array.isArray(dsl.nodes)
|
|
2959
2935
|
? (dsl.nodes as Array<Record<string, unknown>>)
|
|
@@ -2961,128 +2937,41 @@ function buildRetryCheckpoint(
|
|
|
2961
2937
|
const edges = Array.isArray(dsl.edges)
|
|
2962
2938
|
? (dsl.edges as Array<Record<string, unknown>>)
|
|
2963
2939
|
: [];
|
|
2964
|
-
const target = nodes.find((node) => node.id ===
|
|
2965
|
-
if (!target)
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2940
|
+
const target = nodes.find((node) => node.id === nodeId);
|
|
2941
|
+
if (!target) return '失败节点不在原发布版本中';
|
|
2942
|
+
const nodeType = String(target.type ?? '');
|
|
2943
|
+
if (nodeType.endsWith('_trigger')) return '触发节点不能重试';
|
|
2944
|
+
const isCompositeOwner = nodeType === 'parallel' || nodeType === 'for_each';
|
|
2969
2945
|
if (
|
|
2946
|
+
!isCompositeOwner &&
|
|
2970
2947
|
edges.some(
|
|
2971
2948
|
(edge) =>
|
|
2972
2949
|
typeof edge.pairId === 'string' &&
|
|
2973
2950
|
edge.pairId.length > 0 &&
|
|
2974
|
-
(edge.source ===
|
|
2951
|
+
(edge.source === nodeId || edge.target === nodeId),
|
|
2975
2952
|
)
|
|
2976
|
-
)
|
|
2977
|
-
|
|
2978
|
-
}
|
|
2979
|
-
|
|
2980
|
-
const executionMap = new Map<
|
|
2981
|
-
string,
|
|
2982
|
-
{ nodeId: string; status: string; output: unknown }
|
|
2983
|
-
>();
|
|
2984
|
-
for (const completedNodeId of inheritedCheckpoint?.completedNodeIds ?? []) {
|
|
2985
|
-
executionMap.set(completedNodeId, {
|
|
2986
|
-
nodeId: completedNodeId,
|
|
2987
|
-
status: 'COMPLETED',
|
|
2988
|
-
output: inheritedCheckpoint?.outputs[completedNodeId],
|
|
2989
|
-
});
|
|
2990
|
-
}
|
|
2991
|
-
for (const execution of nodeExecutions) {
|
|
2992
|
-
executionMap.set(execution.nodeId, execution);
|
|
2993
|
-
}
|
|
2994
|
-
if (executionMap.get(retryFromNodeId)?.status !== 'FAILED') {
|
|
2995
|
-
throw new BadRequestException('只能从实际失败的节点重试');
|
|
2996
|
-
}
|
|
2997
|
-
|
|
2998
|
-
const mainPredecessors = new Map<string, string[]>();
|
|
2999
|
-
for (const edge of edges) {
|
|
3000
|
-
if (
|
|
3001
|
-
(edge.kind === undefined || edge.kind === 'FLOW') &&
|
|
3002
|
-
!edge.pairId &&
|
|
3003
|
-
typeof edge.source === 'string' &&
|
|
3004
|
-
typeof edge.target === 'string'
|
|
3005
|
-
) {
|
|
3006
|
-
const predecessors = mainPredecessors.get(edge.target) ?? [];
|
|
3007
|
-
predecessors.push(edge.source);
|
|
3008
|
-
mainPredecessors.set(edge.target, predecessors);
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
|
|
3012
|
-
const nodeMap = new Map(
|
|
3013
|
-
nodes
|
|
3014
|
-
.filter((node) => typeof node.id === 'string')
|
|
3015
|
-
.map((node) => [String(node.id), node]),
|
|
3016
|
-
);
|
|
3017
|
-
const ancestors = new Set<string>();
|
|
3018
|
-
const pending = [...(mainPredecessors.get(retryFromNodeId) ?? [])];
|
|
3019
|
-
while (pending.length > 0) {
|
|
3020
|
-
const current = pending.pop();
|
|
3021
|
-
if (!current) continue;
|
|
3022
|
-
if (ancestors.has(current)) continue;
|
|
3023
|
-
ancestors.add(current);
|
|
3024
|
-
pending.push(...(mainPredecessors.get(current) ?? []));
|
|
3025
|
-
}
|
|
3026
|
-
|
|
3027
|
-
const completedNodeIds: string[] = [];
|
|
3028
|
-
const outputs: Record<string, unknown> = {};
|
|
3029
|
-
for (const node of nodes) {
|
|
3030
|
-
const ancestorId = typeof node.id === 'string' ? node.id : '';
|
|
3031
|
-
if (!ancestorId || !ancestors.has(ancestorId)) continue;
|
|
3032
|
-
if (String(node.type).endsWith('_trigger')) continue;
|
|
3033
|
-
const execution = executionMap.get(ancestorId);
|
|
3034
|
-
if (execution?.status !== 'COMPLETED') {
|
|
3035
|
-
throw new BadRequestException(
|
|
3036
|
-
`节点“${String(
|
|
3037
|
-
node.label || node.type || ancestorId,
|
|
3038
|
-
)}”没有可复用的成功结果`,
|
|
3039
|
-
);
|
|
3040
|
-
}
|
|
3041
|
-
completedNodeIds.push(ancestorId);
|
|
3042
|
-
outputs[ancestorId] = execution.output;
|
|
3043
|
-
}
|
|
3044
|
-
|
|
3045
|
-
const immediatePredecessors = mainPredecessors.get(retryFromNodeId) ?? [];
|
|
3046
|
-
if (immediatePredecessors.length > 1) {
|
|
3047
|
-
throw new BadRequestException('失败节点存在多个上游,暂不支持从这里重试');
|
|
3048
|
-
}
|
|
2953
|
+
)
|
|
2954
|
+
return '请从外层循环或并行节点重试';
|
|
3049
2955
|
if (
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
)
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
}
|
|
3058
|
-
|
|
3059
|
-
return { startNodeId: retryFromNodeId, completedNodeIds, outputs };
|
|
2956
|
+
!nodeExecutions.some(
|
|
2957
|
+
(execution) =>
|
|
2958
|
+
execution.nodeId === nodeId && execution.status === 'FAILED',
|
|
2959
|
+
)
|
|
2960
|
+
)
|
|
2961
|
+
return '只能重试当前失败的节点';
|
|
2962
|
+
return undefined;
|
|
3060
2963
|
}
|
|
3061
2964
|
|
|
3062
|
-
function
|
|
2965
|
+
function listSameRunRetryableNodeIds(
|
|
3063
2966
|
dsl: unknown,
|
|
3064
|
-
nodeExecutions: Array<{
|
|
3065
|
-
nodeId: string;
|
|
3066
|
-
status: string;
|
|
3067
|
-
output: unknown;
|
|
3068
|
-
}>,
|
|
3069
|
-
inheritedCheckpoint?: WorkflowRetryCheckpoint,
|
|
2967
|
+
nodeExecutions: Array<{ nodeId: string; status: string }>,
|
|
3070
2968
|
): string[] {
|
|
3071
2969
|
return nodeExecutions
|
|
3072
2970
|
.filter((execution) => execution.status === 'FAILED')
|
|
3073
|
-
.filter(
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
nodeExecutions,
|
|
3078
|
-
execution.nodeId,
|
|
3079
|
-
inheritedCheckpoint,
|
|
3080
|
-
);
|
|
3081
|
-
return true;
|
|
3082
|
-
} catch {
|
|
3083
|
-
return false;
|
|
3084
|
-
}
|
|
3085
|
-
})
|
|
2971
|
+
.filter(
|
|
2972
|
+
(execution) =>
|
|
2973
|
+
!validateSameRunRetryTarget(dsl, nodeExecutions, execution.nodeId),
|
|
2974
|
+
)
|
|
3086
2975
|
.map((execution) => execution.nodeId);
|
|
3087
2976
|
}
|
|
3088
2977
|
|
|
@@ -139,7 +139,9 @@ export class SubjectConfigValidatorService {
|
|
|
139
139
|
|
|
140
140
|
const source = entry.source ?? 'STATIC';
|
|
141
141
|
const provider =
|
|
142
|
-
source === 'DYNAMIC'
|
|
142
|
+
source === 'DYNAMIC'
|
|
143
|
+
? 'USER'
|
|
144
|
+
: (validProvider(entry.provider) ?? 'USER');
|
|
143
145
|
const rawRefs = entry.refs;
|
|
144
146
|
if (source === 'DYNAMIC') {
|
|
145
147
|
const inputKey = validNonBlankString(entry.inputKey);
|
|
@@ -171,7 +171,7 @@ export class WorkflowNodeInstanceController {
|
|
|
171
171
|
@ACAttrFilter() acAttrFilter,
|
|
172
172
|
@Req() request: AuthenticatedActorRequest,
|
|
173
173
|
) {
|
|
174
|
-
/*
|
|
174
|
+
/*
|
|
175
175
|
const origin = (await this.workflowNodeInstanceService.findUnique(id, {
|
|
176
176
|
id: true,
|
|
177
177
|
// 这里需要根据实际情况填写
|