@oneuptime/common 7.0.4748 → 7.0.4755
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/Server/Services/AlertService.ts +222 -109
- package/Server/Services/IncidentService.ts +290 -147
- package/Server/Services/MonitorService.ts +22 -21
- package/Server/Services/ScheduledMaintenanceService.ts +201 -111
- package/Server/Services/StatusPageService.ts +8 -6
- package/build/dist/Server/Services/AlertService.js +190 -88
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +246 -109
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +19 -15
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +152 -78
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +6 -3
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/package.json +1 -1
|
@@ -62,6 +62,7 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
|
62
62
|
import { Dictionary } from "lodash";
|
|
63
63
|
import MetricType from "../../Models/DatabaseModels/MetricType";
|
|
64
64
|
import UpdateBy from "../Types/Database/UpdateBy";
|
|
65
|
+
import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
|
|
65
66
|
|
|
66
67
|
// key is incidentId for this dictionary.
|
|
67
68
|
type UpdateCarryForward = Dictionary<{
|
|
@@ -544,6 +545,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
544
545
|
throw new BadDataException("id is required");
|
|
545
546
|
}
|
|
546
547
|
|
|
548
|
+
// Get incident data for feed creation
|
|
547
549
|
const incident: Model | null = await this.findOneById({
|
|
548
550
|
id: createdItem.id,
|
|
549
551
|
select: {
|
|
@@ -576,202 +578,343 @@ export class Service extends DatabaseService<Model> {
|
|
|
576
578
|
throw new BadDataException("Incident not found");
|
|
577
579
|
}
|
|
578
580
|
|
|
579
|
-
//
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
581
|
+
// Execute core operations in parallel first
|
|
582
|
+
const coreOperations: Array<Promise<any>> = [];
|
|
583
|
+
|
|
584
|
+
// Create feed item asynchronously
|
|
585
|
+
coreOperations.push(this.createIncidentFeedAsync(incident, createdItem));
|
|
586
|
+
|
|
587
|
+
// Handle state change asynchronously
|
|
588
|
+
coreOperations.push(this.handleIncidentStateChangeAsync(createdItem));
|
|
589
|
+
|
|
590
|
+
// Handle owner assignment asynchronously
|
|
591
|
+
if (
|
|
592
|
+
onCreate.createBy.miscDataProps &&
|
|
593
|
+
(onCreate.createBy.miscDataProps["ownerTeams"] ||
|
|
594
|
+
onCreate.createBy.miscDataProps["ownerUsers"])
|
|
595
|
+
) {
|
|
596
|
+
coreOperations.push(
|
|
597
|
+
this.addOwners(
|
|
598
|
+
createdItem.projectId,
|
|
599
|
+
createdItem.id,
|
|
600
|
+
(onCreate.createBy.miscDataProps["ownerUsers"] as Array<ObjectID>) ||
|
|
601
|
+
[],
|
|
602
|
+
(onCreate.createBy.miscDataProps["ownerTeams"] as Array<ObjectID>) ||
|
|
603
|
+
[],
|
|
604
|
+
false,
|
|
605
|
+
onCreate.createBy.props,
|
|
606
|
+
),
|
|
607
|
+
);
|
|
601
608
|
}
|
|
602
609
|
|
|
603
|
-
|
|
604
|
-
|
|
610
|
+
// Handle monitor status change and active monitoring asynchronously
|
|
611
|
+
if (createdItem.changeMonitorStatusToId && createdItem.projectId) {
|
|
612
|
+
coreOperations.push(
|
|
613
|
+
this.handleMonitorStatusChangeAsync(createdItem, onCreate),
|
|
614
|
+
);
|
|
615
|
+
}
|
|
605
616
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
} | null =
|
|
610
|
-
await IncidentWorkspaceMessages.createChannelsAndInviteUsersToChannels({
|
|
611
|
-
projectId: createdItem.projectId,
|
|
612
|
-
incidentId: createdItem.id!,
|
|
613
|
-
incidentNumber: createdItem.incidentNumber!,
|
|
614
|
-
});
|
|
617
|
+
coreOperations.push(
|
|
618
|
+
this.disableActiveMonitoringIfManualIncident(createdItem.id!),
|
|
619
|
+
);
|
|
615
620
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
621
|
+
// Release mutex immediately
|
|
622
|
+
this.releaseMutexAsync(onCreate, createdItem.projectId!);
|
|
623
|
+
|
|
624
|
+
// Execute core operations in parallel with error handling
|
|
625
|
+
Promise.allSettled(coreOperations)
|
|
626
|
+
.then((coreResults: any[]) => {
|
|
627
|
+
// Log any errors from core operations
|
|
628
|
+
coreResults.forEach((result: any, index: number) => {
|
|
629
|
+
if (result.status === "rejected") {
|
|
630
|
+
logger.error(
|
|
631
|
+
`Core operation ${index} failed in IncidentService.onCreateSuccess: ${result.reason}`,
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// Handle on-call duty policies asynchronously
|
|
637
|
+
if (
|
|
638
|
+
createdItem.onCallDutyPolicies?.length &&
|
|
639
|
+
createdItem.onCallDutyPolicies?.length > 0
|
|
640
|
+
) {
|
|
641
|
+
this.executeOnCallDutyPoliciesAsync(createdItem).catch(
|
|
642
|
+
(error: Error) => {
|
|
643
|
+
logger.error(
|
|
644
|
+
`On-call duty policy execution failed in IncidentService.onCreateSuccess: ${error}`,
|
|
645
|
+
);
|
|
646
|
+
},
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Handle workspace operations after core operations complete
|
|
651
|
+
if (createdItem.projectId && createdItem.id) {
|
|
652
|
+
// Run workspace operations in background without blocking response
|
|
653
|
+
this.handleIncidentWorkspaceOperationsAsync(createdItem).catch(
|
|
654
|
+
(error: Error) => {
|
|
655
|
+
logger.error(
|
|
656
|
+
`Workspace operations failed in IncidentService.onCreateSuccess: ${error}`,
|
|
657
|
+
);
|
|
658
|
+
},
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
})
|
|
662
|
+
.catch((error: Error) => {
|
|
663
|
+
logger.error(
|
|
664
|
+
`Critical error in IncidentService core operations: ${error}`,
|
|
665
|
+
);
|
|
626
666
|
});
|
|
667
|
+
|
|
668
|
+
return createdItem;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
@CaptureSpan()
|
|
672
|
+
private async handleIncidentWorkspaceOperationsAsync(
|
|
673
|
+
createdItem: Model,
|
|
674
|
+
): Promise<void> {
|
|
675
|
+
try {
|
|
676
|
+
if (!createdItem.projectId || !createdItem.id) {
|
|
677
|
+
throw new BadDataException(
|
|
678
|
+
"projectId and id are required for workspace operations",
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// send message to workspaces - slack, teams, etc.
|
|
683
|
+
const workspaceResult: {
|
|
684
|
+
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
|
|
685
|
+
} | null =
|
|
686
|
+
await IncidentWorkspaceMessages.createChannelsAndInviteUsersToChannels({
|
|
687
|
+
projectId: createdItem.projectId,
|
|
688
|
+
incidentId: createdItem.id,
|
|
689
|
+
incidentNumber: createdItem.incidentNumber!,
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
|
|
693
|
+
// update incident with these channels.
|
|
694
|
+
await this.updateOneById({
|
|
695
|
+
id: createdItem.id,
|
|
696
|
+
data: {
|
|
697
|
+
postUpdatesToWorkspaceChannels:
|
|
698
|
+
workspaceResult.channelsCreated || [],
|
|
699
|
+
},
|
|
700
|
+
props: {
|
|
701
|
+
isRoot: true,
|
|
702
|
+
},
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
} catch (error) {
|
|
706
|
+
logger.error(`Error in handleIncidentWorkspaceOperationsAsync: ${error}`);
|
|
707
|
+
throw error;
|
|
627
708
|
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
@CaptureSpan()
|
|
712
|
+
private async createIncidentFeedAsync(
|
|
713
|
+
incident: Model,
|
|
714
|
+
createdItem: Model,
|
|
715
|
+
): Promise<void> {
|
|
716
|
+
try {
|
|
717
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
718
|
+
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
|
628
719
|
|
|
629
|
-
|
|
630
|
-
|
|
720
|
+
let feedInfoInMarkdown: string = `#### 🚨 Incident ${createdItem.incidentNumber?.toString()} Created:
|
|
721
|
+
|
|
631
722
|
**${createdItem.title || "No title provided."}**:
|
|
632
723
|
|
|
633
724
|
${createdItem.description || "No description provided."}
|
|
634
725
|
|
|
635
726
|
`;
|
|
636
727
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
728
|
+
if (incident.currentIncidentState?.name) {
|
|
729
|
+
feedInfoInMarkdown += `🔴 **Incident State**: ${incident.currentIncidentState.name} \n\n`;
|
|
730
|
+
}
|
|
640
731
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
732
|
+
if (incident.incidentSeverity?.name) {
|
|
733
|
+
feedInfoInMarkdown += `⚠️ **Severity**: ${incident.incidentSeverity.name} \n\n`;
|
|
734
|
+
}
|
|
644
735
|
|
|
645
|
-
|
|
646
|
-
|
|
736
|
+
if (incident.monitors && incident.monitors.length > 0) {
|
|
737
|
+
feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
|
|
647
738
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
739
|
+
for (const monitor of incident.monitors) {
|
|
740
|
+
feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
|
|
741
|
+
}
|
|
651
742
|
|
|
652
|
-
|
|
653
|
-
|
|
743
|
+
feedInfoInMarkdown += `\n\n`;
|
|
744
|
+
}
|
|
654
745
|
|
|
655
|
-
|
|
656
|
-
|
|
746
|
+
if (createdItem.rootCause) {
|
|
747
|
+
feedInfoInMarkdown += `\n
|
|
657
748
|
📄 **Root Cause**:
|
|
658
749
|
|
|
659
750
|
${createdItem.rootCause || "No root cause provided."}
|
|
660
751
|
|
|
661
752
|
`;
|
|
662
|
-
|
|
753
|
+
}
|
|
663
754
|
|
|
664
|
-
|
|
665
|
-
|
|
755
|
+
if (createdItem.remediationNotes) {
|
|
756
|
+
feedInfoInMarkdown += `\n
|
|
666
757
|
🎯 **Remediation Notes**:
|
|
667
758
|
|
|
668
759
|
${createdItem.remediationNotes || "No remediation notes provided."}
|
|
669
760
|
|
|
670
761
|
|
|
671
762
|
`;
|
|
672
|
-
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const incidentCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
|
|
766
|
+
await IncidentWorkspaceMessages.getIncidentCreateMessageBlocks({
|
|
767
|
+
incidentId: createdItem.id!,
|
|
768
|
+
projectId: createdItem.projectId!,
|
|
769
|
+
});
|
|
673
770
|
|
|
674
|
-
|
|
675
|
-
await IncidentWorkspaceMessages.getIncidentCreateMessageBlocks({
|
|
771
|
+
await IncidentFeedService.createIncidentFeedItem({
|
|
676
772
|
incidentId: createdItem.id!,
|
|
677
773
|
projectId: createdItem.projectId!,
|
|
774
|
+
incidentFeedEventType: IncidentFeedEventType.IncidentCreated,
|
|
775
|
+
displayColor: Red500,
|
|
776
|
+
feedInfoInMarkdown: feedInfoInMarkdown,
|
|
777
|
+
userId: createdByUserId || undefined,
|
|
778
|
+
workspaceNotification: {
|
|
779
|
+
appendMessageBlocks: incidentCreateMessageBlocks,
|
|
780
|
+
sendWorkspaceNotification: true,
|
|
781
|
+
},
|
|
678
782
|
});
|
|
783
|
+
} catch (error) {
|
|
784
|
+
logger.error(`Error in createIncidentFeedAsync: ${error}`);
|
|
785
|
+
throw error;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
679
788
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
appendMessageBlocks: incidentCreateMessageBlocks,
|
|
689
|
-
sendWorkspaceNotification: true,
|
|
690
|
-
},
|
|
691
|
-
});
|
|
789
|
+
@CaptureSpan()
|
|
790
|
+
private async handleIncidentStateChangeAsync(
|
|
791
|
+
createdItem: Model,
|
|
792
|
+
): Promise<void> {
|
|
793
|
+
try {
|
|
794
|
+
if (!createdItem.currentIncidentStateId) {
|
|
795
|
+
throw new BadDataException("currentIncidentStateId is required");
|
|
796
|
+
}
|
|
692
797
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
798
|
+
if (!createdItem.projectId || !createdItem.id) {
|
|
799
|
+
throw new BadDataException(
|
|
800
|
+
"projectId and id are required for state change",
|
|
801
|
+
);
|
|
802
|
+
}
|
|
696
803
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
createdItem.
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
804
|
+
await this.changeIncidentState({
|
|
805
|
+
projectId: createdItem.projectId,
|
|
806
|
+
incidentId: createdItem.id,
|
|
807
|
+
incidentStateId: createdItem.currentIncidentStateId,
|
|
808
|
+
shouldNotifyStatusPageSubscribers: Boolean(
|
|
809
|
+
createdItem.shouldStatusPageSubscribersBeNotifiedOnIncidentCreated,
|
|
810
|
+
),
|
|
811
|
+
isSubscribersNotified: Boolean(
|
|
812
|
+
createdItem.shouldStatusPageSubscribersBeNotifiedOnIncidentCreated,
|
|
813
|
+
), // we dont want to notify subscribers when incident state changes because they are already notified when the incident is created.
|
|
814
|
+
notifyOwners: false,
|
|
815
|
+
rootCause: createdItem.rootCause,
|
|
816
|
+
stateChangeLog: createdItem.createdStateLog,
|
|
817
|
+
props: {
|
|
818
|
+
isRoot: true,
|
|
819
|
+
},
|
|
820
|
+
});
|
|
821
|
+
} catch (error) {
|
|
822
|
+
logger.error(`Error in handleIncidentStateChangeAsync: ${error}`);
|
|
823
|
+
throw error;
|
|
713
824
|
}
|
|
825
|
+
}
|
|
714
826
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
827
|
+
@CaptureSpan()
|
|
828
|
+
private async executeOnCallDutyPoliciesAsync(
|
|
829
|
+
createdItem: Model,
|
|
830
|
+
): Promise<void> {
|
|
831
|
+
try {
|
|
832
|
+
if (
|
|
833
|
+
createdItem.onCallDutyPolicies?.length &&
|
|
834
|
+
createdItem.onCallDutyPolicies?.length > 0
|
|
835
|
+
) {
|
|
836
|
+
// Execute all on-call policies in parallel
|
|
837
|
+
const policyPromises: Promise<void>[] =
|
|
838
|
+
createdItem.onCallDutyPolicies.map((policy: OnCallDutyPolicy) => {
|
|
839
|
+
return OnCallDutyPolicyService.executePolicy(
|
|
840
|
+
new ObjectID(policy["_id"] as string),
|
|
841
|
+
{
|
|
842
|
+
triggeredByIncidentId: createdItem.id!,
|
|
843
|
+
userNotificationEventType:
|
|
844
|
+
UserNotificationEventType.IncidentCreated,
|
|
845
|
+
},
|
|
846
|
+
);
|
|
847
|
+
});
|
|
734
848
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
await this.addOwners(
|
|
741
|
-
createdItem.projectId,
|
|
742
|
-
createdItem.id,
|
|
743
|
-
(onCreate.createBy.miscDataProps["ownerUsers"] as Array<ObjectID>) ||
|
|
744
|
-
[],
|
|
745
|
-
(onCreate.createBy.miscDataProps["ownerTeams"] as Array<ObjectID>) ||
|
|
746
|
-
[],
|
|
747
|
-
false,
|
|
748
|
-
onCreate.createBy.props,
|
|
749
|
-
);
|
|
849
|
+
await Promise.allSettled(policyPromises);
|
|
850
|
+
}
|
|
851
|
+
} catch (error) {
|
|
852
|
+
logger.error(`Error in executeOnCallDutyPoliciesAsync: ${error}`);
|
|
853
|
+
throw error;
|
|
750
854
|
}
|
|
855
|
+
}
|
|
751
856
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
857
|
+
@CaptureSpan()
|
|
858
|
+
private async handleMonitorStatusChangeAsync(
|
|
859
|
+
createdItem: Model,
|
|
860
|
+
onCreate: OnCreate<Model>,
|
|
861
|
+
): Promise<void> {
|
|
862
|
+
try {
|
|
863
|
+
if (createdItem.changeMonitorStatusToId && createdItem.projectId) {
|
|
864
|
+
// change status of all the monitors.
|
|
865
|
+
await MonitorService.changeMonitorStatus(
|
|
866
|
+
createdItem.projectId,
|
|
867
|
+
createdItem.monitors?.map((monitor: Monitor) => {
|
|
868
|
+
return new ObjectID(monitor._id || "");
|
|
869
|
+
}) || [],
|
|
870
|
+
createdItem.changeMonitorStatusToId,
|
|
871
|
+
true, // notifyMonitorOwners
|
|
872
|
+
createdItem.rootCause ||
|
|
873
|
+
"Status was changed because Incident #" +
|
|
874
|
+
createdItem.incidentNumber?.toString() +
|
|
875
|
+
" was created.",
|
|
876
|
+
createdItem.createdStateLog,
|
|
877
|
+
onCreate.createBy.props,
|
|
764
878
|
);
|
|
765
879
|
}
|
|
880
|
+
} catch (error) {
|
|
881
|
+
logger.error(`Error in handleMonitorStatusChangeAsync: ${error}`);
|
|
882
|
+
throw error;
|
|
766
883
|
}
|
|
884
|
+
}
|
|
767
885
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
886
|
+
@CaptureSpan()
|
|
887
|
+
private releaseMutexAsync(
|
|
888
|
+
onCreate: OnCreate<Model>,
|
|
889
|
+
projectId: ObjectID,
|
|
890
|
+
): void {
|
|
891
|
+
// Release mutex in background without blocking
|
|
892
|
+
if (onCreate.carryForward && onCreate.carryForward.mutex) {
|
|
893
|
+
const mutex: SemaphoreMutex = onCreate.carryForward.mutex;
|
|
771
894
|
|
|
772
|
-
|
|
895
|
+
setImmediate(async () => {
|
|
896
|
+
try {
|
|
897
|
+
await Semaphore.release(mutex);
|
|
898
|
+
logger.debug(
|
|
899
|
+
"Mutex released - IncidentService.incident-create " +
|
|
900
|
+
projectId.toString() +
|
|
901
|
+
" at " +
|
|
902
|
+
OneUptimeDate.getCurrentDateAsFormattedString(),
|
|
903
|
+
);
|
|
904
|
+
} catch (err) {
|
|
905
|
+
logger.debug(
|
|
906
|
+
"Mutex release failed - IncidentService.incident-create " +
|
|
907
|
+
projectId.toString() +
|
|
908
|
+
" at " +
|
|
909
|
+
OneUptimeDate.getCurrentDateAsFormattedString(),
|
|
910
|
+
);
|
|
911
|
+
logger.error(err);
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
}
|
|
773
915
|
}
|
|
774
916
|
|
|
917
|
+
@CaptureSpan()
|
|
775
918
|
public async disableActiveMonitoringIfManualIncident(
|
|
776
919
|
incidentId: ObjectID,
|
|
777
920
|
): Promise<void> {
|
|
@@ -516,7 +516,7 @@ ${createdItem.description?.trim() || "No description provided."}
|
|
|
516
516
|
onCreate.createBy.props,
|
|
517
517
|
);
|
|
518
518
|
|
|
519
|
-
// 2. Start
|
|
519
|
+
// 2. Start core operations in parallel that can run asynchronously (excluding workspace operations)
|
|
520
520
|
|
|
521
521
|
// Add default probes if needed (can be slow with many probes)
|
|
522
522
|
if (
|
|
@@ -535,21 +535,6 @@ ${createdItem.description?.trim() || "No description provided."}
|
|
|
535
535
|
);
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
-
// Workspace operations (can be slow due to external API calls)
|
|
539
|
-
parallelOperations.push(
|
|
540
|
-
this.handleWorkspaceOperationsAsync({
|
|
541
|
-
projectId: createdItem.projectId,
|
|
542
|
-
monitorId: createdItem.id!,
|
|
543
|
-
monitorName: createdItem.name!,
|
|
544
|
-
feedInfoInMarkdown,
|
|
545
|
-
createdByUserId,
|
|
546
|
-
}).catch((error: Error) => {
|
|
547
|
-
logger.error("Error in workspace operations");
|
|
548
|
-
logger.error(error);
|
|
549
|
-
// Don't fail monitor creation due to workspace issues
|
|
550
|
-
}),
|
|
551
|
-
);
|
|
552
|
-
|
|
553
538
|
// Billing operations
|
|
554
539
|
if (IsBillingEnabled) {
|
|
555
540
|
parallelOperations.push(
|
|
@@ -596,11 +581,27 @@ ${createdItem.description?.trim() || "No description provided."}
|
|
|
596
581
|
}),
|
|
597
582
|
);
|
|
598
583
|
|
|
599
|
-
// Wait for
|
|
600
|
-
Promise.allSettled(parallelOperations)
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
584
|
+
// Wait for core operations to complete, then handle workspace operations
|
|
585
|
+
Promise.allSettled(parallelOperations)
|
|
586
|
+
.then(() => {
|
|
587
|
+
// Handle workspace operations after core operations complete
|
|
588
|
+
// Run workspace operations in background without blocking response
|
|
589
|
+
this.handleWorkspaceOperationsAsync({
|
|
590
|
+
projectId: createdItem.projectId!,
|
|
591
|
+
monitorId: createdItem.id!,
|
|
592
|
+
monitorName: createdItem.name!,
|
|
593
|
+
feedInfoInMarkdown,
|
|
594
|
+
createdByUserId,
|
|
595
|
+
}).catch((error: Error) => {
|
|
596
|
+
logger.error("Error in workspace operations");
|
|
597
|
+
logger.error(error);
|
|
598
|
+
// Don't fail monitor creation due to workspace issues
|
|
599
|
+
});
|
|
600
|
+
})
|
|
601
|
+
.catch((error: Error) => {
|
|
602
|
+
logger.error("Error in parallel monitor creation operations");
|
|
603
|
+
logger.error(error);
|
|
604
|
+
});
|
|
604
605
|
|
|
605
606
|
return createdItem;
|
|
606
607
|
}
|