Skip to content

Commit

Permalink
feat: implement mutex for incident creation and improve incident numb…
Browse files Browse the repository at this point in the history
…er handling
  • Loading branch information
simlarsen committed Jan 12, 2025
1 parent b66b1db commit 982d051
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 25 deletions.
71 changes: 65 additions & 6 deletions Common/Server/Services/IncidentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ import OneUptimeDate from "../../Types/Date";
import TelemetryUtil from "../Utils/Telemetry/Telemetry";
import TelemetryType from "../../Types/Telemetry/TelemetryType";
import logger from "../Utils/Logger";
import Semaphore, {
SemaphoreMutex,
} from "Common/Server/Infrastructure/Semaphore";

export class Service extends DatabaseService<Model> {
public constructor() {
Expand Down Expand Up @@ -189,11 +192,6 @@ export class Service extends DatabaseService<Model> {
const projectId: ObjectID =
createBy.props.tenantId || createBy.data.projectId!;

const incidentNumberForThisIncident: number =
(await this.getExistingIncidentNumberForProject({
projectId: projectId,
})) + 1;

const incidentState: IncidentState | null =
await IncidentStateService.findOneBy({
query: {
Expand All @@ -214,6 +212,37 @@ export class Service extends DatabaseService<Model> {
);
}

let mutex: SemaphoreMutex | null = null;

try {
mutex = await Semaphore.lock({
key: projectId.toString(),
namespace: "IncidentService.incident-create",
lockTimeout: 15000,
acquireTimeout: 20000,
});

logger.debug(
"Mutex acquired - IncidentService.incident-create " +
projectId.toString() +
" at " +
OneUptimeDate.getCurrentDateAsFormattedString(),
);
} catch (err) {
logger.debug(
"Mutex acquire failed - IncidentService.incident-create " +
projectId.toString() +
" at " +
OneUptimeDate.getCurrentDateAsFormattedString(),
);
logger.error(err);
}

const incidentNumberForThisIncident: number =
(await this.getExistingIncidentNumberForProject({
projectId: projectId,
})) + 1;

createBy.data.currentIncidentStateId = incidentState.id;
createBy.data.incidentNumber = incidentNumberForThisIncident;

Expand Down Expand Up @@ -252,13 +281,19 @@ export class Service extends DatabaseService<Model> {
}
}

return { createBy, carryForward: null };
return {
createBy,
carryForward: {
mutex: mutex,
},
};
}

protected override async onCreateSuccess(
onCreate: OnCreate<Model>,
createdItem: Model,
): Promise<Model> {
// these should never be null.
if (!createdItem.projectId) {
throw new BadDataException("projectId is required");
}
Expand All @@ -267,6 +302,30 @@ export class Service extends DatabaseService<Model> {
throw new BadDataException("id is required");
}

// release the mutex.
if (onCreate.carryForward && onCreate.carryForward.mutex) {
const mutex: SemaphoreMutex = onCreate.carryForward.mutex;
const projectId: ObjectID = createdItem.projectId!;

try {
await Semaphore.release(mutex);
logger.debug(
"Mutex released - IncidentService.incident-create " +
projectId.toString() +
" at " +
OneUptimeDate.getCurrentDateAsFormattedString(),
);
} catch (err) {
logger.debug(
"Mutex release failed - IncidentService.incident-create " +
projectId.toString() +
" at " +
OneUptimeDate.getCurrentDateAsFormattedString(),
);
logger.error(err);
}
}

if (!createdItem.currentIncidentStateId) {
throw new BadDataException("currentIncidentStateId is required");
}
Expand Down
3 changes: 1 addition & 2 deletions Dashboard/src/Components/Incident/IncidentsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,7 @@ const IncidentsTable: FunctionComponent<ComponentProps> = (
title: "Incident Number",
type: FieldType.Text,
getElement: (item: Incident): ReactElement => {

if(!item.incidentNumber) {
if (!item.incidentNumber) {
return <>-</>;
}

Expand Down
6 changes: 3 additions & 3 deletions Dashboard/src/Pages/Incidents/View/Index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,12 @@ const IncidentView: FunctionComponent<
title: "Incident Number",
fieldType: FieldType.Element,
getElement: (item: Incident): ReactElement => {
if(!item.incidentNumber) {
if (!item.incidentNumber) {
return <>-</>;
}

return <># {item.incidentNumber}</>;
}
},
},
{
field: {
Expand Down
25 changes: 12 additions & 13 deletions Worker/DataMigrations/AddIncidentNumber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default class AddIncidentNumber extends DataMigrationBase {
// first fetch resolved state. Ended state order is -1 of resolved state.

// get all incicents for this project
const incidents: Array<Incident> = await IncidentService.findBy({
const incidents: Array<Incident> = await IncidentService.findBy({
query: {
projectId: project.id!,
},
Expand All @@ -42,30 +42,29 @@ export default class AddIncidentNumber extends DataMigrationBase {
skip: 0,
limit: LIMIT_MAX,
sort: {
createdAt: SortOrder.Descending
createdAt: SortOrder.Descending,
},
props: {
isRoot: true,
},
});

const totalIncidentForProject = incidents.length;
let incidentCounter = totalIncidentForProject; // start from the last incident number
const totalIncidentForProject: number = incidents.length;
let incidentCounter: number = totalIncidentForProject; // start from the last incident number

for(const incident of incidents) {
for (const incident of incidents) {
await IncidentService.updateOneById({
id: incident.id!,
data: {
incidentNumber: incidentCounter,
},
props: {
isRoot: true,
},
id: incident.id!,
data: {
incidentNumber: incidentCounter,
},
props: {
isRoot: true,
},
});

incidentCounter = incidentCounter - 1;
}

}
}

Expand Down
2 changes: 1 addition & 1 deletion Worker/DataMigrations/Index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const DataMigrations: Array<DataMigrationBase> = [
new RefreshDefaultUserNotificationSetting(),
new AddServiceTypeColumnToMetricsTable(),
new AddIsSubscriptionConfirmedToSubscribers(),
new AddIncidentNumber()
new AddIncidentNumber(),
];

export default DataMigrations;

0 comments on commit 982d051

Please sign in to comment.