@oneuptime/common 7.0.5096 → 7.0.5108

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.
@@ -273,109 +273,88 @@ export class Service extends DatabaseService<Model> {
273
273
  throw new BadDataException("currentAlertStateId is required");
274
274
  }
275
275
 
276
- // Get alert data for feed creation
277
- const alert: Model | null = await this.findOneById({
278
- id: createdItem.id,
279
- select: {
280
- projectId: true,
281
- alertNumber: true,
282
- title: true,
283
- description: true,
284
- alertSeverity: {
285
- name: true,
286
- },
287
- rootCause: true,
288
- remediationNotes: true,
289
- currentAlertState: {
290
- name: true,
291
- },
292
- labels: {
293
- name: true,
294
- },
295
- monitor: {
296
- name: true,
297
- _id: true,
298
- },
299
- },
300
- props: {
301
- isRoot: true,
302
- },
303
- });
304
-
305
- if (!alert) {
306
- throw new BadDataException("Alert not found");
307
- }
308
-
309
- // Execute core operations in parallel first
310
- const coreOperations: Array<Promise<any>> = [];
311
-
312
- // Create feed item asynchronously
313
- coreOperations.push(this.createAlertFeedAsync(alert, createdItem));
314
-
315
- // Handle state change asynchronously
316
- coreOperations.push(this.handleAlertStateChangeAsync(createdItem));
317
-
318
- // Handle owner assignment asynchronously
319
- if (
320
- onCreate.createBy.miscDataProps &&
321
- (onCreate.createBy.miscDataProps["ownerTeams"] ||
322
- onCreate.createBy.miscDataProps["ownerUsers"])
323
- ) {
324
- coreOperations.push(
325
- this.addOwners(
326
- createdItem.projectId,
327
- createdItem.id,
328
- (onCreate.createBy.miscDataProps["ownerUsers"] as Array<ObjectID>) ||
329
- [],
330
- (onCreate.createBy.miscDataProps["ownerTeams"] as Array<ObjectID>) ||
331
- [],
332
- false,
333
- onCreate.createBy.props,
334
- ),
335
- );
336
- }
337
-
338
- // Execute core operations in parallel with error handling
339
- Promise.allSettled(coreOperations)
340
- .then((coreResults: any[]) => {
341
- // Log any errors from core operations
342
- coreResults.forEach((result: any, index: number) => {
343
- if (result.status === "rejected") {
276
+ // Execute operations sequentially with error handling
277
+ Promise.resolve()
278
+ .then(async () => {
279
+ if (createdItem.projectId && createdItem.id) {
280
+ try {
281
+ return await this.handleAlertWorkspaceOperationsAsync(createdItem);
282
+ } catch (error) {
344
283
  logger.error(
345
- `Core operation ${index} failed in AlertService.onCreateSuccess: ${result.reason}`,
284
+ `Workspace operations failed in AlertService.onCreateSuccess: ${error}`,
346
285
  );
286
+ return Promise.resolve();
347
287
  }
348
- });
349
-
350
- // Handle on-call duty policies asynchronously
288
+ }
289
+ return Promise.resolve();
290
+ })
291
+ .then(async () => {
292
+ try {
293
+ return await this.createAlertFeedAsync(createdItem.id!);
294
+ } catch (error) {
295
+ logger.error(
296
+ `Create alert feed failed in AlertService.onCreateSuccess: ${error}`,
297
+ );
298
+ return Promise.resolve(); // Continue chain even on error
299
+ }
300
+ })
301
+ .then(async () => {
302
+ try {
303
+ return await this.handleAlertStateChangeAsync(createdItem);
304
+ } catch (error) {
305
+ logger.error(
306
+ `Handle alert state change failed in AlertService.onCreateSuccess: ${error}`,
307
+ );
308
+ return Promise.resolve(); // Continue chain even on error
309
+ }
310
+ })
311
+ .then(async () => {
312
+ try {
313
+ if (
314
+ onCreate.createBy.miscDataProps &&
315
+ (onCreate.createBy.miscDataProps["ownerTeams"] ||
316
+ onCreate.createBy.miscDataProps["ownerUsers"])
317
+ ) {
318
+ return await this.addOwners(
319
+ createdItem.projectId!,
320
+ createdItem.id!,
321
+ (onCreate.createBy.miscDataProps![
322
+ "ownerUsers"
323
+ ] as Array<ObjectID>) || [],
324
+ (onCreate.createBy.miscDataProps![
325
+ "ownerTeams"
326
+ ] as Array<ObjectID>) || [],
327
+ false,
328
+ onCreate.createBy.props,
329
+ );
330
+ }
331
+ return Promise.resolve();
332
+ } catch (error) {
333
+ logger.error(
334
+ `Add owners failed in AlertService.onCreateSuccess: ${error}`,
335
+ );
336
+ return Promise.resolve(); // Continue chain even on error
337
+ }
338
+ })
339
+ .then(async () => {
351
340
  if (
352
341
  createdItem.onCallDutyPolicies?.length &&
353
342
  createdItem.onCallDutyPolicies?.length > 0
354
343
  ) {
355
- this.executeAlertOnCallDutyPoliciesAsync(createdItem).catch(
356
- (error: Error) => {
357
- logger.error(
358
- `On-call duty policy execution failed in AlertService.onCreateSuccess: ${error}`,
359
- );
360
- },
361
- );
362
- }
363
-
364
- // Handle workspace operations after core operations complete
365
- if (createdItem.projectId && createdItem.id) {
366
- // Run workspace operations in background without blocking response
367
- this.handleAlertWorkspaceOperationsAsync(createdItem).catch(
368
- (error: Error) => {
369
- logger.error(
370
- `Workspace operations failed in AlertService.onCreateSuccess: ${error}`,
371
- );
372
- },
373
- );
344
+ try {
345
+ return await this.executeAlertOnCallDutyPoliciesAsync(createdItem);
346
+ } catch (error) {
347
+ logger.error(
348
+ `On-call duty policy execution failed in AlertService.onCreateSuccess: ${error}`,
349
+ );
350
+ return Promise.resolve();
351
+ }
374
352
  }
353
+ return Promise.resolve();
375
354
  })
376
355
  .catch((error: Error) => {
377
356
  logger.error(
378
- `Critical error in AlertService core operations: ${error}`,
357
+ `Critical error in AlertService sequential operations: ${error}`,
379
358
  );
380
359
  });
381
360
 
@@ -426,19 +405,55 @@ export class Service extends DatabaseService<Model> {
426
405
  }
427
406
 
428
407
  @CaptureSpan()
429
- private async createAlertFeedAsync(
430
- alert: Model,
431
- createdItem: Model,
432
- ): Promise<void> {
408
+ private async createAlertFeedAsync(alertId: ObjectID): Promise<void> {
433
409
  try {
410
+ // Get alert data for feed creation
411
+ const alert: Model | null = await this.findOneById({
412
+ id: alertId,
413
+ select: {
414
+ projectId: true,
415
+ alertNumber: true,
416
+ title: true,
417
+ description: true,
418
+ alertSeverity: {
419
+ name: true,
420
+ },
421
+ rootCause: true,
422
+ createdByUserId: true,
423
+ createdByUser: {
424
+ _id: true,
425
+ name: true,
426
+ email: true,
427
+ },
428
+ remediationNotes: true,
429
+ currentAlertState: {
430
+ name: true,
431
+ },
432
+ labels: {
433
+ name: true,
434
+ },
435
+ monitor: {
436
+ name: true,
437
+ _id: true,
438
+ },
439
+ },
440
+ props: {
441
+ isRoot: true,
442
+ },
443
+ });
444
+
445
+ if (!alert) {
446
+ throw new BadDataException("Alert not found");
447
+ }
448
+
434
449
  const createdByUserId: ObjectID | undefined | null =
435
- createdItem.createdByUserId || createdItem.createdByUser?.id;
450
+ alert.createdByUserId || alert.createdByUser?.id;
436
451
 
437
- let feedInfoInMarkdown: string = `#### 🚨 Alert ${createdItem.alertNumber?.toString()} Created:
452
+ let feedInfoInMarkdown: string = `#### 🚨 Alert ${alert.alertNumber?.toString()} Created:
438
453
 
439
- **${createdItem.title || "No title provided."}**:
454
+ **${alert.title || "No title provided."}**:
440
455
 
441
- ${createdItem.description || "No description provided."}
456
+ ${alert.description || "No description provided."}
442
457
 
443
458
  `;
444
459
 
@@ -454,25 +469,25 @@ ${createdItem.description || "No description provided."}
454
469
  feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
455
470
 
456
471
  const monitor: Monitor = alert.monitor;
457
- feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
472
+ feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(alert.projectId!, monitor.id!)).toString()})\n`;
458
473
 
459
474
  feedInfoInMarkdown += `\n\n`;
460
475
  }
461
476
 
462
- if (createdItem.rootCause) {
477
+ if (alert.rootCause) {
463
478
  feedInfoInMarkdown += `\n
464
479
  📄 **Root Cause**:
465
480
 
466
- ${createdItem.rootCause || "No root cause provided."}
481
+ ${alert.rootCause || "No root cause provided."}
467
482
 
468
483
  `;
469
484
  }
470
485
 
471
- if (createdItem.remediationNotes) {
486
+ if (alert.remediationNotes) {
472
487
  feedInfoInMarkdown += `\n
473
488
  🎯 **Remediation Notes**:
474
489
 
475
- ${createdItem.remediationNotes || "No remediation notes provided."}
490
+ ${alert.remediationNotes || "No remediation notes provided."}
476
491
 
477
492
 
478
493
  `;
@@ -480,13 +495,13 @@ ${createdItem.remediationNotes || "No remediation notes provided."}
480
495
 
481
496
  const alertCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
482
497
  await AlertWorkspaceMessages.getAlertCreateMessageBlocks({
483
- alertId: createdItem.id!,
484
- projectId: createdItem.projectId!,
498
+ alertId: alert.id!,
499
+ projectId: alert.projectId!,
485
500
  });
486
501
 
487
502
  await AlertFeedService.createAlertFeedItem({
488
- alertId: createdItem.id!,
489
- projectId: createdItem.projectId!,
503
+ alertId: alert.id!,
504
+ projectId: alert.projectId!,
490
505
  alertFeedEventType: AlertFeedEventType.AlertCreated,
491
506
  displayColor: Red500,
492
507
  feedInfoInMarkdown: feedInfoInMarkdown,
@@ -597,6 +597,12 @@ export class Service extends DatabaseService<Model> {
597
597
  name: true,
598
598
  },
599
599
  rootCause: true,
600
+ createdByUserId: true,
601
+ createdByUser: {
602
+ _id: true,
603
+ name: true,
604
+ email: true,
605
+ },
600
606
  remediationNotes: true,
601
607
  currentIncidentState: {
602
608
  name: true,
@@ -618,90 +624,121 @@ export class Service extends DatabaseService<Model> {
618
624
  throw new BadDataException("Incident not found");
619
625
  }
620
626
 
621
- // Execute core operations in parallel first
622
- const coreOperations: Array<Promise<any>> = [];
623
-
624
- // Create feed item asynchronously
625
- coreOperations.push(this.createIncidentFeedAsync(incident, createdItem));
626
-
627
- // Handle state change asynchronously
628
- coreOperations.push(this.handleIncidentStateChangeAsync(createdItem));
629
-
630
- // Handle owner assignment asynchronously
631
- if (
632
- onCreate.createBy.miscDataProps &&
633
- (onCreate.createBy.miscDataProps["ownerTeams"] ||
634
- onCreate.createBy.miscDataProps["ownerUsers"])
635
- ) {
636
- coreOperations.push(
637
- this.addOwners(
638
- createdItem.projectId,
639
- createdItem.id,
640
- (onCreate.createBy.miscDataProps["ownerUsers"] as Array<ObjectID>) ||
641
- [],
642
- (onCreate.createBy.miscDataProps["ownerTeams"] as Array<ObjectID>) ||
643
- [],
644
- false,
645
- onCreate.createBy.props,
646
- ),
647
- );
648
- }
649
-
650
- // Handle monitor status change and active monitoring asynchronously
651
- if (createdItem.changeMonitorStatusToId && createdItem.projectId) {
652
- coreOperations.push(
653
- this.handleMonitorStatusChangeAsync(createdItem, onCreate),
654
- );
655
- }
656
-
657
- coreOperations.push(
658
- this.disableActiveMonitoringIfManualIncident(createdItem.id!),
659
- );
660
-
661
627
  // Release mutex immediately
662
628
  this.releaseMutexAsync(onCreate, createdItem.projectId!);
663
629
 
664
- // Execute core operations in parallel with error handling
665
- Promise.allSettled(coreOperations)
666
- .then((coreResults: any[]) => {
667
- // Log any errors from core operations
668
- coreResults.forEach((result: any, index: number) => {
669
- if (result.status === "rejected") {
670
- logger.error(
671
- `Core operation ${index} failed in IncidentService.onCreateSuccess: ${result.reason}`,
630
+ // Execute operations sequentially with error handling
631
+ Promise.resolve()
632
+ .then(async () => {
633
+ try {
634
+ if (createdItem.projectId && createdItem.id) {
635
+ return await this.handleIncidentWorkspaceOperationsAsync(
636
+ createdItem,
672
637
  );
673
638
  }
674
- });
675
-
676
- // Handle on-call duty policies asynchronously
677
- if (
678
- createdItem.onCallDutyPolicies?.length &&
679
- createdItem.onCallDutyPolicies?.length > 0
680
- ) {
681
- this.executeOnCallDutyPoliciesAsync(createdItem).catch(
682
- (error: Error) => {
683
- logger.error(
684
- `On-call duty policy execution failed in IncidentService.onCreateSuccess: ${error}`,
685
- );
686
- },
639
+ return Promise.resolve();
640
+ } catch (error) {
641
+ logger.error(
642
+ `Workspace operations failed in IncidentService.onCreateSuccess: ${error}`,
687
643
  );
644
+ return Promise.resolve();
688
645
  }
689
-
690
- // Handle workspace operations after core operations complete
691
- if (createdItem.projectId && createdItem.id) {
692
- // Run workspace operations in background without blocking response
693
- this.handleIncidentWorkspaceOperationsAsync(createdItem).catch(
694
- (error: Error) => {
695
- logger.error(
696
- `Workspace operations failed in IncidentService.onCreateSuccess: ${error}`,
697
- );
698
- },
646
+ })
647
+ .then(async () => {
648
+ try {
649
+ return await this.createIncidentFeedAsync(incident);
650
+ } catch (error) {
651
+ logger.error(
652
+ `Create incident feed failed in IncidentService.onCreateSuccess: ${error}`,
653
+ );
654
+ return Promise.resolve();
655
+ }
656
+ })
657
+ .then(async () => {
658
+ try {
659
+ return await this.handleIncidentStateChangeAsync(createdItem);
660
+ } catch (error) {
661
+ logger.error(
662
+ `Handle incident state change failed in IncidentService.onCreateSuccess: ${error}`,
663
+ );
664
+ return Promise.resolve();
665
+ }
666
+ })
667
+ .then(async () => {
668
+ try {
669
+ if (
670
+ onCreate.createBy.miscDataProps &&
671
+ (onCreate.createBy.miscDataProps["ownerTeams"] ||
672
+ onCreate.createBy.miscDataProps["ownerUsers"])
673
+ ) {
674
+ return await this.addOwners(
675
+ createdItem.projectId!,
676
+ createdItem.id!,
677
+ (onCreate.createBy.miscDataProps[
678
+ "ownerUsers"
679
+ ] as Array<ObjectID>) || [],
680
+ (onCreate.createBy.miscDataProps[
681
+ "ownerTeams"
682
+ ] as Array<ObjectID>) || [],
683
+ false,
684
+ onCreate.createBy.props,
685
+ );
686
+ }
687
+ return Promise.resolve();
688
+ } catch (error) {
689
+ logger.error(
690
+ `Add owners failed in IncidentService.onCreateSuccess: ${error}`,
691
+ );
692
+ return Promise.resolve();
693
+ }
694
+ })
695
+ .then(async () => {
696
+ try {
697
+ if (createdItem.changeMonitorStatusToId && createdItem.projectId) {
698
+ return await this.handleMonitorStatusChangeAsync(
699
+ createdItem,
700
+ onCreate,
701
+ );
702
+ }
703
+ return Promise.resolve();
704
+ } catch (error) {
705
+ logger.error(
706
+ `Monitor status change failed in IncidentService.onCreateSuccess: ${error}`,
707
+ );
708
+ return Promise.resolve();
709
+ }
710
+ })
711
+ .then(async () => {
712
+ try {
713
+ return await this.disableActiveMonitoringIfManualIncident(
714
+ createdItem.id!,
715
+ );
716
+ } catch (error) {
717
+ logger.error(
718
+ `Disable active monitoring failed in IncidentService.onCreateSuccess: ${error}`,
719
+ );
720
+ return Promise.resolve();
721
+ }
722
+ })
723
+ .then(async () => {
724
+ try {
725
+ if (
726
+ createdItem.onCallDutyPolicies?.length &&
727
+ createdItem.onCallDutyPolicies?.length > 0
728
+ ) {
729
+ return await this.executeOnCallDutyPoliciesAsync(createdItem);
730
+ }
731
+ return Promise.resolve();
732
+ } catch (error) {
733
+ logger.error(
734
+ `On-call duty policy execution failed in IncidentService.onCreateSuccess: ${error}`,
699
735
  );
736
+ return Promise.resolve();
700
737
  }
701
738
  })
702
739
  .catch((error: Error) => {
703
740
  logger.error(
704
- `Critical error in IncidentService core operations: ${error}`,
741
+ `Critical error in IncidentService sequential operations: ${error}`,
705
742
  );
706
743
  });
707
744
 
@@ -749,19 +786,16 @@ export class Service extends DatabaseService<Model> {
749
786
  }
750
787
 
751
788
  @CaptureSpan()
752
- private async createIncidentFeedAsync(
753
- incident: Model,
754
- createdItem: Model,
755
- ): Promise<void> {
789
+ private async createIncidentFeedAsync(incident: Model): Promise<void> {
756
790
  try {
757
791
  const createdByUserId: ObjectID | undefined | null =
758
- createdItem.createdByUserId || createdItem.createdByUser?.id;
792
+ incident.createdByUserId || incident.createdByUser?.id;
759
793
 
760
- let feedInfoInMarkdown: string = `#### 🚨 Incident ${createdItem.incidentNumber?.toString()} Created:
794
+ let feedInfoInMarkdown: string = `#### 🚨 Incident ${incident.incidentNumber?.toString()} Created:
761
795
 
762
- **${createdItem.title || "No title provided."}**:
796
+ **${incident.title || "No title provided."}**:
763
797
 
764
- ${createdItem.description || "No description provided."}
798
+ ${incident.description || "No description provided."}
765
799
 
766
800
  `;
767
801
 
@@ -777,26 +811,26 @@ ${createdItem.description || "No description provided."}
777
811
  feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
778
812
 
779
813
  for (const monitor of incident.monitors) {
780
- feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
814
+ feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(incident.projectId!, monitor.id!)).toString()})\n`;
781
815
  }
782
816
 
783
817
  feedInfoInMarkdown += `\n\n`;
784
818
  }
785
819
 
786
- if (createdItem.rootCause) {
820
+ if (incident.rootCause) {
787
821
  feedInfoInMarkdown += `\n
788
822
  📄 **Root Cause**:
789
823
 
790
- ${createdItem.rootCause || "No root cause provided."}
824
+ ${incident.rootCause || "No root cause provided."}
791
825
 
792
826
  `;
793
827
  }
794
828
 
795
- if (createdItem.remediationNotes) {
829
+ if (incident.remediationNotes) {
796
830
  feedInfoInMarkdown += `\n
797
831
  🎯 **Remediation Notes**:
798
832
 
799
- ${createdItem.remediationNotes || "No remediation notes provided."}
833
+ ${incident.remediationNotes || "No remediation notes provided."}
800
834
 
801
835
 
802
836
  `;
@@ -804,13 +838,13 @@ ${createdItem.remediationNotes || "No remediation notes provided."}
804
838
 
805
839
  const incidentCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
806
840
  await IncidentWorkspaceMessages.getIncidentCreateMessageBlocks({
807
- incidentId: createdItem.id!,
808
- projectId: createdItem.projectId!,
841
+ incidentId: incident.id!,
842
+ projectId: incident.projectId!,
809
843
  });
810
844
 
811
845
  await IncidentFeedService.createIncidentFeedItem({
812
- incidentId: createdItem.id!,
813
- projectId: createdItem.projectId!,
846
+ incidentId: incident.id!,
847
+ projectId: incident.projectId!,
814
848
  incidentFeedEventType: IncidentFeedEventType.IncidentCreated,
815
849
  displayColor: Red500,
816
850
  feedInfoInMarkdown: feedInfoInMarkdown,