@oneuptime/common 11.5.12 → 11.6.0
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/Models/DatabaseModels/AIInsight.ts +30 -0
- package/Models/DatabaseModels/EnterpriseLicense.ts +21 -0
- package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +25 -0
- package/Models/DatabaseModels/GlobalConfig.ts +76 -0
- package/Models/DatabaseModels/Project.ts +30 -0
- package/Models/DatabaseModels/TelemetryException.ts +128 -0
- package/Server/API/AIAgentDataAPI.ts +129 -5
- package/Server/API/AIInvestigationAPI.ts +87 -0
- package/Server/API/EnterpriseLicenseAPI.ts +57 -0
- package/Server/API/GlobalConfigAPI.ts +62 -1
- package/Server/EnvironmentConfig.ts +22 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784640000000-AddExceptionTriageAndPrivacyColumns.ts +56 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.ts +38 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/AIRunService.ts +8 -0
- package/Server/Services/AnalyticsDatabaseService.ts +48 -45
- package/Server/Services/DatabaseService.ts +66 -1
- package/Server/Services/TelemetryExceptionService.ts +320 -24
- package/Server/Services/WorkflowService.ts +100 -39
- package/Server/Types/Workflow/Components/Schedule.ts +57 -32
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +15 -4
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +15 -4
- package/Server/Utils/AI/SRE/Insights/InsightScanner.ts +222 -24
- package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +225 -9
- package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +39 -0
- package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +114 -0
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +59 -0
- package/Server/Utils/Express.ts +13 -0
- package/Server/Utils/Telemetry/ExceptionSanitizer.ts +222 -0
- package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +799 -0
- package/Server/Utils/Telemetry/TelemetryWriterClient.ts +263 -0
- package/Server/Utils/Telemetry/TelemetryWriterServer.ts +240 -0
- package/Server/Utils/Telemetry/TelemetryWriterShedMetrics.ts +93 -0
- package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +232 -0
- package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +205 -1
- package/Tests/Server/Services/UpdateOneByIdKeepsRowId.test.ts +107 -0
- package/Tests/Server/Services/WorkflowService.test.ts +308 -0
- package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +150 -141
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +277 -1
- package/Tests/Server/Utils/Attribution.test.ts +203 -0
- package/Tests/Server/Utils/ExceptionSanitizer.test.ts +70 -0
- package/Tests/Server/Utils/InsightTriageClassification.test.ts +57 -0
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +183 -0
- package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +340 -0
- package/Tests/Server/Utils/Monitor/Criteria/ExceptionMonitorCriteria.test.ts +87 -0
- package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +165 -0
- package/Tests/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.test.ts +86 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +1565 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterClient.test.ts +313 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterServer.test.ts +270 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterShedMetrics.test.ts +127 -0
- package/Tests/Server/Utils/TelemetryImprovementTaskTrigger.test.ts +141 -0
- package/Tests/Types/AI/CodeFixTaskType.test.ts +3 -0
- package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +228 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +169 -0
- package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +289 -0
- package/Tests/Types/Monitor/MonitorStepLogMonitor.test.ts +231 -0
- package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +245 -0
- package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +155 -0
- package/Tests/Types/Monitor/MonitorStepTelemetrySerialization.test.ts +141 -0
- package/Tests/Types/Monitor/MonitorStepTraceMonitor.test.ts +137 -0
- package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +311 -0
- package/Tests/UI/Components/ModelTableSelectFromColumns.test.ts +259 -0
- package/Tests/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.test.ts +461 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +2852 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +758 -0
- package/Tests/UI/Utils/NotificationMethodUtil.test.ts +564 -0
- package/Tests/Utils/Array.test.ts +156 -0
- package/Tests/Utils/CronTab.test.ts +199 -0
- package/Tests/Utils/ModelImportExport.test.ts +101 -0
- package/Tests/Utils/Number.test.ts +179 -0
- package/Tests/Utils/VersionUtil.test.ts +348 -0
- package/Tests/jest.setup.ts +1 -0
- package/Types/AI/CodeFixTaskContext.ts +6 -0
- package/Types/AI/CodeFixTaskType.ts +38 -1
- package/Types/AI/ExceptionAIClassification.ts +27 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +6 -0
- package/Types/Log/LogScrubPatternType.ts +7 -0
- package/Types/Monitor/MonitorStep.ts +24 -4
- package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +105 -0
- package/Types/Trace/TraceScrubPatternType.ts +7 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +445 -12
- package/UI/Components/ModelTable/BaseModelTable.tsx +15 -46
- package/UI/Components/ModelTable/SelectFromColumns.ts +129 -0
- package/UI/Components/Workflow/ArgumentsForm.tsx +68 -30
- package/UI/Components/Workflow/CronScheduleField.tsx +411 -0
- package/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.ts +176 -0
- package/UI/Utils/NotificationMethodUtil.ts +310 -0
- package/Utils/CronTab.ts +823 -0
- package/Utils/ModelImportExport.ts +21 -6
- package/Utils/VersionUtil.ts +260 -0
- package/build/dist/Models/DatabaseModels/AIInsight.js +31 -0
- package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +22 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +26 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +81 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +31 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +134 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +97 -8
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +55 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +47 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +52 -1
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +17 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784640000000-AddExceptionTriageAndPrivacyColumns.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784640000000-AddExceptionTriageAndPrivacyColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +9 -2
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +44 -16
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +53 -1
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +263 -22
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowService.js +80 -30
- package/build/dist/Server/Services/WorkflowService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Schedule.js +44 -19
- package/build/dist/Server/Types/Workflow/Components/Schedule.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +12 -4
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +12 -4
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js +193 -22
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +178 -9
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +37 -0
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +98 -0
- package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js +24 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -0
- package/build/dist/Server/Utils/Express.js +12 -0
- package/build/dist/Server/Utils/Express.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +149 -0
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +496 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js +165 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js +136 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js +76 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js.map +1 -0
- package/build/dist/Types/AI/CodeFixTaskType.js +38 -1
- package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -1
- package/build/dist/Types/AI/ExceptionAIClassification.js +28 -0
- package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -0
- package/build/dist/Types/Log/LogScrubPatternType.js +7 -0
- package/build/dist/Types/Log/LogScrubPatternType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +20 -4
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +73 -0
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -0
- package/build/dist/Types/Trace/TraceScrubPatternType.js +7 -0
- package/build/dist/Types/Trace/TraceScrubPatternType.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +261 -13
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +12 -37
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/SelectFromColumns.js +82 -0
- package/build/dist/UI/Components/ModelTable/SelectFromColumns.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +30 -6
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/CronScheduleField.js +209 -0
- package/build/dist/UI/Components/Workflow/CronScheduleField.js.map +1 -0
- package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js +129 -0
- package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js.map +1 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js +189 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -0
- package/build/dist/Utils/CronTab.js +609 -0
- package/build/dist/Utils/CronTab.js.map +1 -0
- package/build/dist/Utils/ModelImportExport.js +20 -6
- package/build/dist/Utils/ModelImportExport.js.map +1 -1
- package/build/dist/Utils/VersionUtil.js +193 -0
- package/build/dist/Utils/VersionUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -1743,10 +1743,67 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
1743
1743
|
});
|
|
1744
1744
|
}
|
|
1745
1745
|
|
|
1746
|
+
/*
|
|
1747
|
+
* Update `data` may arrive as a full model instance rather than a plain
|
|
1748
|
+
* partial — the QueryDeepPartialEntity type structurally admits both, and
|
|
1749
|
+
* callers do construct `new Model()` payloads. A model instance carries
|
|
1750
|
+
* non-column own properties from DatabaseBaseModel (every column
|
|
1751
|
+
* initializer plus `isPermissionIf = {}`), and _updateBy turns every data
|
|
1752
|
+
* key into a select column for its internal find, so the extra keys made
|
|
1753
|
+
* that find throw `TableColumnMetadata not found for isPermissionIf
|
|
1754
|
+
* column` and fail the whole update. Strip a model instance down to its
|
|
1755
|
+
* set table columns; plain objects pass through untouched so a typo'd
|
|
1756
|
+
* column name in a literal still fails loudly instead of being silently
|
|
1757
|
+
* dropped.
|
|
1758
|
+
*
|
|
1759
|
+
* `_id`, `createdAt`, `updatedAt` and `version` are dropped for model
|
|
1760
|
+
* instances the same way BaseAPI drops them from client payloads: the row
|
|
1761
|
+
* is located by the update query (spreading a foreign `_id` into the save
|
|
1762
|
+
* payload would redirect the write), timestamps are database-managed, and
|
|
1763
|
+
* `version` is TypeORM's optimistic-concurrency counter.
|
|
1764
|
+
*/
|
|
1765
|
+
public sanitizeUpdateData(
|
|
1766
|
+
data: UpdateBy<TBaseModel>["data"],
|
|
1767
|
+
): UpdateBy<TBaseModel>["data"] {
|
|
1768
|
+
if (!(data instanceof BaseModel)) {
|
|
1769
|
+
return data;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
const plainData: JSONObject = {};
|
|
1773
|
+
|
|
1774
|
+
for (const key of Object.keys(data)) {
|
|
1775
|
+
if (!this.model.isTableColumn(key)) {
|
|
1776
|
+
continue;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
if (
|
|
1780
|
+
key === "_id" ||
|
|
1781
|
+
key === "createdAt" ||
|
|
1782
|
+
key === "updatedAt" ||
|
|
1783
|
+
key === "version"
|
|
1784
|
+
) {
|
|
1785
|
+
continue;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
const value: JSONValue = (data as any)[key];
|
|
1789
|
+
|
|
1790
|
+
// Unset columns must not become writes (or select columns).
|
|
1791
|
+
if (value === undefined) {
|
|
1792
|
+
continue;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
plainData[key] = value;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
return plainData as UpdateBy<TBaseModel>["data"];
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1746
1801
|
private async _updateBy(updateBy: UpdateBy<TBaseModel>): Promise<number> {
|
|
1747
1802
|
try {
|
|
1748
1803
|
this.setTelemetryContextFromProps(updateBy.props);
|
|
1749
1804
|
|
|
1805
|
+
updateBy.data = this.sanitizeUpdateData(updateBy.data);
|
|
1806
|
+
|
|
1750
1807
|
const onUpdate: OnUpdate<TBaseModel> = updateBy.props.ignoreHooks
|
|
1751
1808
|
? { updateBy, carryForward: [] }
|
|
1752
1809
|
: await this.onBeforeUpdate(updateBy);
|
|
@@ -1830,9 +1887,17 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
1830
1887
|
});
|
|
1831
1888
|
|
|
1832
1889
|
for (const item of items) {
|
|
1890
|
+
/*
|
|
1891
|
+
* _id must be set AFTER the spread: update data can carry an
|
|
1892
|
+
* explicit `_id: undefined` (sanitizeUpdateData strips it from model
|
|
1893
|
+
* instances, but a plain object can still hold it), and spreading it
|
|
1894
|
+
* after _id would clobber the located row's id — save() then sees no
|
|
1895
|
+
* primary key, INSERTs instead of updating, and dies on the first
|
|
1896
|
+
* NOT NULL column.
|
|
1897
|
+
*/
|
|
1833
1898
|
const updatedItem: any = {
|
|
1834
|
-
_id: item._id!,
|
|
1835
1899
|
...data,
|
|
1900
|
+
_id: item._id!,
|
|
1836
1901
|
} as any;
|
|
1837
1902
|
|
|
1838
1903
|
logger.debug("Updated Item", {
|
|
@@ -28,6 +28,12 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
|
28
28
|
import Query from "../Types/Database/Query";
|
|
29
29
|
import Includes from "../../Types/BaseDatabase/Includes";
|
|
30
30
|
import logger from "../Utils/Logger";
|
|
31
|
+
import AIAgentTaskPullRequest from "../../Models/DatabaseModels/AIAgentTaskPullRequest";
|
|
32
|
+
import AIAgentTaskPullRequestService from "./AIAgentTaskPullRequestService";
|
|
33
|
+
import PullRequestState from "../../Types/CodeRepository/PullRequestState";
|
|
34
|
+
import { normalizeExceptionText } from "../Utils/Telemetry/ExceptionSanitizer";
|
|
35
|
+
import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
|
|
36
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
31
37
|
|
|
32
38
|
/*
|
|
33
39
|
* Hard cap on the fingerprint NOT IN list handed to the ClickHouse count
|
|
@@ -221,6 +227,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
221
227
|
select: {
|
|
222
228
|
_id: true,
|
|
223
229
|
projectId: true,
|
|
230
|
+
message: true,
|
|
231
|
+
exceptionType: true,
|
|
232
|
+
isResolved: true,
|
|
233
|
+
isArchived: true,
|
|
234
|
+
aiFixDeclinedAt: true,
|
|
224
235
|
},
|
|
225
236
|
props,
|
|
226
237
|
});
|
|
@@ -229,6 +240,45 @@ export class Service extends DatabaseService<Model> {
|
|
|
229
240
|
throw new BadDataException("Telemetry Exception not found");
|
|
230
241
|
}
|
|
231
242
|
|
|
243
|
+
/*
|
|
244
|
+
* Server-side lifecycle gate (the dashboard hides the button for
|
|
245
|
+
* resolved exceptions, but the API must enforce it — the automatic
|
|
246
|
+
* insight lane and any direct API caller land here too).
|
|
247
|
+
*/
|
|
248
|
+
if (telemetryException.isResolved) {
|
|
249
|
+
throw new BadDataException(
|
|
250
|
+
"This exception is marked as resolved. Unresolve it before starting an AI agent task for it.",
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (telemetryException.isArchived) {
|
|
255
|
+
throw new BadDataException(
|
|
256
|
+
"This exception is archived. Unarchive it before starting an AI agent task for it.",
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
* Human "closed without merging" feedback: when an AI FIX PR for this
|
|
262
|
+
* exception was declined, the automatic lane must not keep re-opening
|
|
263
|
+
* fix PRs for it. Scoped to the FixException recipe — the stamp is only
|
|
264
|
+
* ever SET for closed fix PRs (SyncPullRequestStates), so a regression
|
|
265
|
+
* test or error-handling task is neither blocked by it nor allowed to
|
|
266
|
+
* clear it. A HUMAN clicking "Fix with AI" is the explicit override;
|
|
267
|
+
* the stamp is cleared only AFTER the retry run is actually created
|
|
268
|
+
* (see below), so a retry that fails a later gate leaves the human's
|
|
269
|
+
* decline in force.
|
|
270
|
+
*/
|
|
271
|
+
const isDeclinedFixOverride: boolean = Boolean(
|
|
272
|
+
telemetryException.aiFixDeclinedAt &&
|
|
273
|
+
taskType === CodeFixTaskType.FixException,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
if (isDeclinedFixOverride && !props.userId) {
|
|
277
|
+
throw new BadDataException(
|
|
278
|
+
"A previous AI fix pull request for this exception was closed without merging, so automatic fix attempts are paused for it. A user can retry from the exception page.",
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
232
282
|
/*
|
|
233
283
|
* G11 guardrail: the per-project daily fix-run budget. Checked before
|
|
234
284
|
* the (more expensive) readiness probes — an over-budget project gets
|
|
@@ -261,38 +311,107 @@ export class Service extends DatabaseService<Model> {
|
|
|
261
311
|
}
|
|
262
312
|
|
|
263
313
|
/*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
314
|
+
* The duplicate guards below are check-then-create: without
|
|
315
|
+
* serialization, two triage completions for splintered variants of the
|
|
316
|
+
* same root cause can both pass the guards and both create runs. A
|
|
317
|
+
* per-project Redis mutex closes the window; acquisition failure
|
|
318
|
+
* (Redis down) degrades to the unserialized behavior rather than
|
|
319
|
+
* blocking fix creation — the guards still run, they just race.
|
|
266
320
|
*/
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
321
|
+
let mutex: SemaphoreMutex | null = null;
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
mutex = await Semaphore.lock({
|
|
325
|
+
key: telemetryException.projectId.toString(),
|
|
326
|
+
namespace: "TelemetryExceptionService.createCodeFixRunForException",
|
|
327
|
+
lockTimeout: 15000,
|
|
328
|
+
});
|
|
329
|
+
} catch (err) {
|
|
330
|
+
logger.debug(
|
|
331
|
+
`Could not acquire the code-fix creation mutex for project ${telemetryException.projectId.toString()} — proceeding without serialization: ${err}`,
|
|
332
|
+
);
|
|
279
333
|
}
|
|
280
334
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
335
|
+
let createdRun: AIRun;
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
/*
|
|
339
|
+
* Duplicate guard is per (exception, taskType): an active
|
|
340
|
+
* FixException run must not block queuing a WriteRegressionTest run
|
|
341
|
+
* and vice versa.
|
|
342
|
+
*/
|
|
343
|
+
await this.validateNoActiveCodeFixRunExists(
|
|
344
|
+
telemetryExceptionId,
|
|
345
|
+
taskType,
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
/*
|
|
349
|
+
* Cross-group duplicate guard: interpolated dynamic values (garbage
|
|
350
|
+
* UUIDs, file paths, request payloads) splinter one root cause into
|
|
351
|
+
* many fingerprints, and the per-exception guard above cannot see
|
|
352
|
+
* that. Compare NORMALIZED messages against exceptions that already
|
|
353
|
+
* have an active run or an open AI pull request, so one root cause
|
|
354
|
+
* yields one PR — not one per interpolated variant.
|
|
355
|
+
*/
|
|
356
|
+
await this.validateNoOpenFixForSimilarException({
|
|
357
|
+
projectId: telemetryException.projectId,
|
|
358
|
+
telemetryExceptionId: telemetryExceptionId,
|
|
359
|
+
taskType: taskType,
|
|
360
|
+
message: telemetryException.message || "",
|
|
361
|
+
exceptionType: telemetryException.exceptionType || "",
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const run: AIRun = new AIRun();
|
|
365
|
+
run.projectId = telemetryException.projectId;
|
|
366
|
+
run.runType = AIRunType.CodeFix;
|
|
367
|
+
run.codeFixTaskType = taskType;
|
|
368
|
+
run.status = AIRunStatus.Queued;
|
|
369
|
+
run.triggeredByTelemetryExceptionId = telemetryExceptionId;
|
|
370
|
+
|
|
371
|
+
// Attribution: the user who clicked "Fix with AI Agent".
|
|
372
|
+
if (props.userId) {
|
|
373
|
+
run.userId = props.userId;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/*
|
|
377
|
+
* Created as root: AIRun rows are server-written only (empty create
|
|
378
|
+
* ACL); the user's access was already checked by the exception read.
|
|
379
|
+
*/
|
|
380
|
+
createdRun = await AIRunService.create({
|
|
381
|
+
data: run,
|
|
382
|
+
props: {
|
|
383
|
+
isRoot: true,
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
} finally {
|
|
387
|
+
if (mutex) {
|
|
388
|
+
try {
|
|
389
|
+
await Semaphore.release(mutex);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
logger.debug(`Failed to release the code-fix creation mutex: ${err}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
291
395
|
|
|
292
396
|
if (!createdRun.id) {
|
|
293
397
|
throw new BadDataException("Failed to create the AI fix run");
|
|
294
398
|
}
|
|
295
399
|
|
|
400
|
+
/*
|
|
401
|
+
* The human's retry actually went through — only now consume the
|
|
402
|
+
* decline override. A retry that failed any gate above leaves the
|
|
403
|
+
* suppression in force.
|
|
404
|
+
*/
|
|
405
|
+
if (isDeclinedFixOverride) {
|
|
406
|
+
await this.updateOneById({
|
|
407
|
+
id: telemetryExceptionId,
|
|
408
|
+
data: {
|
|
409
|
+
aiFixDeclinedAt: null,
|
|
410
|
+
},
|
|
411
|
+
props: { isRoot: true },
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
296
415
|
return createdRun;
|
|
297
416
|
}
|
|
298
417
|
|
|
@@ -338,6 +457,183 @@ export class Service extends DatabaseService<Model> {
|
|
|
338
457
|
}
|
|
339
458
|
}
|
|
340
459
|
|
|
460
|
+
/*
|
|
461
|
+
* Cross-group duplicate guard. Two exception groups are "the same work"
|
|
462
|
+
* for the fix lane when their exceptionType and NORMALIZED message match
|
|
463
|
+
* (normalizeExceptionText replaces UUIDs, IDs, emails, paths' dynamic
|
|
464
|
+
* segments, timestamps...). Candidates are the exceptions behind
|
|
465
|
+
* (a) non-terminal CodeFix runs of the same recipe, and (b) OPEN
|
|
466
|
+
* AI-authored pull requests — a completed run whose PR is still open
|
|
467
|
+
* must keep blocking, or every interpolated variant re-fixes the same
|
|
468
|
+
* root cause (observed: 15 near-identical PRs for one invalid-uuid
|
|
469
|
+
* throw site).
|
|
470
|
+
*/
|
|
471
|
+
@CaptureSpan()
|
|
472
|
+
private async validateNoOpenFixForSimilarException(data: {
|
|
473
|
+
projectId: ObjectID;
|
|
474
|
+
telemetryExceptionId: ObjectID;
|
|
475
|
+
taskType: CodeFixTaskType;
|
|
476
|
+
message: string;
|
|
477
|
+
exceptionType: string;
|
|
478
|
+
}): Promise<void> {
|
|
479
|
+
// (a) Exceptions with a non-terminal run of the same recipe.
|
|
480
|
+
const activeRuns: Array<AIRun> = await AIRunService.findBy({
|
|
481
|
+
query: {
|
|
482
|
+
projectId: data.projectId,
|
|
483
|
+
runType: AIRunType.CodeFix,
|
|
484
|
+
/*
|
|
485
|
+
* A null codeFixTaskType means FixException (rows created before
|
|
486
|
+
* task recipes existed) — same legacy-null matching as
|
|
487
|
+
* validateNoActiveCodeFixRunExists.
|
|
488
|
+
*/
|
|
489
|
+
codeFixTaskType:
|
|
490
|
+
data.taskType === CodeFixTaskType.FixException
|
|
491
|
+
? QueryHelper.equalToOrNull(CodeFixTaskType.FixException)
|
|
492
|
+
: data.taskType,
|
|
493
|
+
status: QueryHelper.notIn([
|
|
494
|
+
AIRunStatus.Completed,
|
|
495
|
+
AIRunStatus.NoFixFound,
|
|
496
|
+
AIRunStatus.Error,
|
|
497
|
+
AIRunStatus.Cancelled,
|
|
498
|
+
AIRunStatus.Stale,
|
|
499
|
+
]),
|
|
500
|
+
},
|
|
501
|
+
select: {
|
|
502
|
+
triggeredByTelemetryExceptionId: true,
|
|
503
|
+
},
|
|
504
|
+
limit: LIMIT_MAX,
|
|
505
|
+
skip: 0,
|
|
506
|
+
props: { isRoot: true },
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// (b) Exceptions behind still-open AI pull requests.
|
|
510
|
+
const openPullRequests: Array<AIAgentTaskPullRequest> =
|
|
511
|
+
await AIAgentTaskPullRequestService.findBy({
|
|
512
|
+
query: {
|
|
513
|
+
projectId: data.projectId,
|
|
514
|
+
pullRequestState: PullRequestState.Open,
|
|
515
|
+
},
|
|
516
|
+
select: {
|
|
517
|
+
aiRunId: true,
|
|
518
|
+
},
|
|
519
|
+
limit: LIMIT_MAX,
|
|
520
|
+
skip: 0,
|
|
521
|
+
props: { isRoot: true },
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
/*
|
|
525
|
+
* A guard that silently stops guarding is worse than none — surface
|
|
526
|
+
* candidate-scan truncation instead of quietly missing duplicates.
|
|
527
|
+
*/
|
|
528
|
+
if (
|
|
529
|
+
activeRuns.length >= LIMIT_MAX ||
|
|
530
|
+
openPullRequests.length >= LIMIT_MAX
|
|
531
|
+
) {
|
|
532
|
+
logger.warn(
|
|
533
|
+
`Cross-group AI fix dedupe guard: candidate scan truncated at ${LIMIT_MAX} rows for project ${data.projectId.toString()} — the duplicate-PR guard may miss matches.`,
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const openPrRunIds: Array<ObjectID> = openPullRequests
|
|
538
|
+
.map((pullRequest: AIAgentTaskPullRequest) => {
|
|
539
|
+
return pullRequest.aiRunId;
|
|
540
|
+
})
|
|
541
|
+
.filter((runId: ObjectID | undefined): runId is ObjectID => {
|
|
542
|
+
return Boolean(runId);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
const openPrRuns: Array<AIRun> =
|
|
546
|
+
openPrRunIds.length > 0
|
|
547
|
+
? await AIRunService.findBy({
|
|
548
|
+
query: {
|
|
549
|
+
_id: new Includes(openPrRunIds),
|
|
550
|
+
projectId: data.projectId,
|
|
551
|
+
runType: AIRunType.CodeFix,
|
|
552
|
+
codeFixTaskType:
|
|
553
|
+
data.taskType === CodeFixTaskType.FixException
|
|
554
|
+
? QueryHelper.equalToOrNull(CodeFixTaskType.FixException)
|
|
555
|
+
: data.taskType,
|
|
556
|
+
},
|
|
557
|
+
select: {
|
|
558
|
+
triggeredByTelemetryExceptionId: true,
|
|
559
|
+
},
|
|
560
|
+
limit: LIMIT_MAX,
|
|
561
|
+
skip: 0,
|
|
562
|
+
props: { isRoot: true },
|
|
563
|
+
})
|
|
564
|
+
: [];
|
|
565
|
+
|
|
566
|
+
/*
|
|
567
|
+
* The target exception is deliberately NOT excluded: its own COMPLETED
|
|
568
|
+
* run with a still-open PR must keep blocking a re-fix (the
|
|
569
|
+
* non-terminal guard above cannot see completed runs). Its own ACTIVE
|
|
570
|
+
* runs were already rejected by validateNoActiveCodeFixRunExists.
|
|
571
|
+
*/
|
|
572
|
+
const candidateExceptionIds: Array<ObjectID> = [];
|
|
573
|
+
const seenIds: Set<string> = new Set<string>();
|
|
574
|
+
|
|
575
|
+
for (const run of [...activeRuns, ...openPrRuns]) {
|
|
576
|
+
const exceptionId: ObjectID | undefined =
|
|
577
|
+
run.triggeredByTelemetryExceptionId;
|
|
578
|
+
|
|
579
|
+
if (!exceptionId) {
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const idString: string = exceptionId.toString();
|
|
584
|
+
|
|
585
|
+
if (seenIds.has(idString)) {
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
seenIds.add(idString);
|
|
590
|
+
candidateExceptionIds.push(exceptionId);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (candidateExceptionIds.length === 0) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const targetSignature: string = `${data.exceptionType}|${normalizeExceptionText(
|
|
598
|
+
data.message,
|
|
599
|
+
)}`;
|
|
600
|
+
|
|
601
|
+
const candidates: Array<Model> = await this.findBy({
|
|
602
|
+
query: {
|
|
603
|
+
projectId: data.projectId,
|
|
604
|
+
_id: new Includes(candidateExceptionIds),
|
|
605
|
+
},
|
|
606
|
+
select: {
|
|
607
|
+
_id: true,
|
|
608
|
+
message: true,
|
|
609
|
+
exceptionType: true,
|
|
610
|
+
},
|
|
611
|
+
limit: candidateExceptionIds.length,
|
|
612
|
+
skip: 0,
|
|
613
|
+
props: { isRoot: true },
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
for (const candidate of candidates) {
|
|
617
|
+
const candidateSignature: string = `${candidate.exceptionType || ""}|${normalizeExceptionText(
|
|
618
|
+
candidate.message || "",
|
|
619
|
+
)}`;
|
|
620
|
+
|
|
621
|
+
if (candidateSignature !== targetSignature) {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (candidate._id?.toString() === data.telemetryExceptionId.toString()) {
|
|
626
|
+
throw new BadDataException(
|
|
627
|
+
"This exception already has an open AI pull request for this task type. Review that pull request instead of opening another one.",
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
throw new BadDataException(
|
|
632
|
+
`A similar exception (same type and normalized message, exception ${candidate._id?.toString()}) already has an AI agent task in progress or an open AI pull request. Review that pull request instead of opening another one for the same root cause.`,
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
341
637
|
@CaptureSpan()
|
|
342
638
|
public async getDashboardSummary(
|
|
343
639
|
props: DatabaseCommonInteractionProps,
|
|
@@ -49,6 +49,40 @@ export class Service extends DatabaseService<Model> {
|
|
|
49
49
|
createdItem.webhookSecretKey = secretKey;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/*
|
|
53
|
+
* A workflow that arrives with its graph already in place - imported from
|
|
54
|
+
* a JSON export, or duplicated from another workflow - never passes
|
|
55
|
+
* through onUpdateSuccess, so nothing has denormalized its trigger onto
|
|
56
|
+
* the row. The runner looks workflows up by triggerId, so without this the
|
|
57
|
+
* workflow is saved and looks correct in the builder but silently never
|
|
58
|
+
* fires.
|
|
59
|
+
*/
|
|
60
|
+
if (createdItem.id && createdItem.graph) {
|
|
61
|
+
await this.saveTriggerFromGraph({
|
|
62
|
+
workflowId: createdItem.id,
|
|
63
|
+
graph: createdItem.graph,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* Registers schedule triggers with the runner. Best effort: the row and
|
|
68
|
+
* its trigger are already persisted, so a workflow service outage must
|
|
69
|
+
* not fail the create. The trigger is already on the row, so the next
|
|
70
|
+
* save - or the runner's own startup scan in Schedule.init, which
|
|
71
|
+
* queries by triggerId - picks the workflow up.
|
|
72
|
+
*/
|
|
73
|
+
try {
|
|
74
|
+
await this.notifyWorkflowService(createdItem.id);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logger.error(
|
|
77
|
+
`Error notifying workflow service of created workflow: ${error}`,
|
|
78
|
+
{
|
|
79
|
+
projectId: createdItem.projectId?.toString(),
|
|
80
|
+
workflowId: createdItem.id?.toString(),
|
|
81
|
+
} as LogAttributes,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
52
86
|
if (createdItem.projectId && createdItem.id) {
|
|
53
87
|
/*
|
|
54
88
|
* Run label rule first so rule-added labels are persisted before
|
|
@@ -87,39 +121,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
87
121
|
): Promise<OnUpdate<Model>> {
|
|
88
122
|
/// save trigger and trigger args.
|
|
89
123
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
(onUpdate.updateBy.data as any).graph &&
|
|
93
|
-
(((onUpdate.updateBy.data as any).graph as any)[
|
|
94
|
-
"nodes"
|
|
95
|
-
] as Array<JSONObject>)
|
|
96
|
-
) {
|
|
97
|
-
let trigger: NodeDataProp | null = null;
|
|
98
|
-
|
|
99
|
-
// check if it has a trigger node.
|
|
100
|
-
for (const node of ((onUpdate.updateBy.data as any).graph as any)[
|
|
101
|
-
"nodes"
|
|
102
|
-
] as Array<JSONObject>) {
|
|
103
|
-
const nodeData: NodeDataProp = node["data"] as any;
|
|
104
|
-
if (
|
|
105
|
-
nodeData.componentType === ComponentType.Trigger &&
|
|
106
|
-
nodeData.nodeType === NodeType.Node
|
|
107
|
-
) {
|
|
108
|
-
// found the trigger;
|
|
109
|
-
trigger = nodeData;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
124
|
+
const updatedGraph: JSONObject | undefined = (onUpdate.updateBy.data as any)
|
|
125
|
+
?.graph as JSONObject | undefined;
|
|
112
126
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
triggerArguments: trigger?.arguments || {},
|
|
118
|
-
} as any,
|
|
119
|
-
props: {
|
|
120
|
-
isRoot: true,
|
|
121
|
-
ignoreHooks: true,
|
|
122
|
-
},
|
|
127
|
+
if (updatedGraph) {
|
|
128
|
+
await this.saveTriggerFromGraph({
|
|
129
|
+
workflowId: new ObjectID(onUpdate.updateBy.query._id! as any),
|
|
130
|
+
graph: updatedGraph,
|
|
123
131
|
});
|
|
124
132
|
}
|
|
125
133
|
|
|
@@ -127,23 +135,76 @@ export class Service extends DatabaseService<Model> {
|
|
|
127
135
|
workflowId: onUpdate.updateBy.query._id?.toString(),
|
|
128
136
|
} as LogAttributes);
|
|
129
137
|
|
|
138
|
+
await this.notifyWorkflowService(
|
|
139
|
+
new ObjectID(onUpdate.updateBy.query._id! as any),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
logger.debug("Updated workflow on the workflow service", {
|
|
143
|
+
workflowId: onUpdate.updateBy.query._id?.toString(),
|
|
144
|
+
} as LogAttributes);
|
|
145
|
+
|
|
146
|
+
return onUpdate;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
* The trigger node is denormalized out of the graph onto triggerId /
|
|
151
|
+
* triggerArguments because the runner queries workflows by trigger and
|
|
152
|
+
* cannot parse every graph to do it. A graph with no trigger node clears
|
|
153
|
+
* both columns, which is how a workflow stops firing when its trigger is
|
|
154
|
+
* removed in the builder.
|
|
155
|
+
*/
|
|
156
|
+
private async saveTriggerFromGraph(data: {
|
|
157
|
+
workflowId: ObjectID;
|
|
158
|
+
graph: JSONObject;
|
|
159
|
+
}): Promise<void> {
|
|
160
|
+
const nodes: Array<JSONObject> | undefined = data.graph["nodes"] as
|
|
161
|
+
| Array<JSONObject>
|
|
162
|
+
| undefined;
|
|
163
|
+
|
|
164
|
+
if (!nodes || !Array.isArray(nodes)) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let trigger: NodeDataProp | null = null;
|
|
169
|
+
|
|
170
|
+
// check if it has a trigger node.
|
|
171
|
+
for (const node of nodes) {
|
|
172
|
+
const nodeData: NodeDataProp = node["data"] as any;
|
|
173
|
+
|
|
174
|
+
if (
|
|
175
|
+
nodeData?.componentType === ComponentType.Trigger &&
|
|
176
|
+
nodeData?.nodeType === NodeType.Node
|
|
177
|
+
) {
|
|
178
|
+
// found the trigger;
|
|
179
|
+
trigger = nodeData;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
await this.updateOneById({
|
|
184
|
+
id: data.workflowId,
|
|
185
|
+
data: {
|
|
186
|
+
triggerId: trigger?.metadataId || null,
|
|
187
|
+
triggerArguments: trigger?.arguments || {},
|
|
188
|
+
} as any,
|
|
189
|
+
props: {
|
|
190
|
+
isRoot: true,
|
|
191
|
+
ignoreHooks: true,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async notifyWorkflowService(workflowId: ObjectID): Promise<void> {
|
|
130
197
|
await API.post<EmptyResponseData>({
|
|
131
198
|
url: new URL(
|
|
132
199
|
Protocol.HTTP,
|
|
133
200
|
WorkflowHostname,
|
|
134
|
-
new Route("/workflow/update/" +
|
|
201
|
+
new Route("/workflow/update/" + workflowId.toString()),
|
|
135
202
|
),
|
|
136
203
|
data: {},
|
|
137
204
|
headers: {
|
|
138
205
|
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
|
139
206
|
},
|
|
140
207
|
});
|
|
141
|
-
|
|
142
|
-
logger.debug("Updated workflow on the workflow service", {
|
|
143
|
-
workflowId: onUpdate.updateBy.query._id?.toString(),
|
|
144
|
-
} as LogAttributes);
|
|
145
|
-
|
|
146
|
-
return onUpdate;
|
|
147
208
|
}
|
|
148
209
|
}
|
|
149
210
|
export default new Service();
|