Skip to content

Commit

Permalink
chore: include incident to public status (#484)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxkaske authored Nov 24, 2023
1 parent 5696d45 commit b999dd0
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 9 deletions.
10 changes: 10 additions & 0 deletions apps/docs/getting-started/status-widget.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum Status {
MajorOutage = "major_outage",
UnderMaintenance = "under_maintenance", // currently not in use
Unknown = "unknown",
Incident = "incident",
}
```

Expand All @@ -54,6 +55,10 @@ function getStatus(ratio: number) {

We are caching the result for `30 seconds` to reduce the load on our database.

The `Status.Incident` will always be returned when then status of any incident
on your page is **not** _"monitoring"_ or _"resolved"_. You can attach an
incident to a monitor (implicit) or a page (explicit).

> If you have a doubt about the above calculation, feel free to contact us via
> [[email protected]](mailto:[email protected]) or
> [discord](https://openstatus.dev/discord).
Expand Down Expand Up @@ -82,6 +87,7 @@ const statusEnum = z.enum([
"major_outage",
"under_maintenance",
"unknown",
"incident",
]);

const statusSchema = z.object({ status: statusEnum });
Expand All @@ -107,6 +113,10 @@ const dictionary = {
label: "Unknown",
color: "bg-gray-500",
},
incident: {
label: "Incident",
color: "bg-yellow-500",
},
under_maintenance: {
label: "Under Maintenance",
color: "bg-gray-500",
Expand Down
33 changes: 31 additions & 2 deletions apps/server/src/public/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { Hono } from "hono";
import { endTime, setMetric, startTime } from "hono/timing";

import { db, eq } from "@openstatus/db";
import { monitor, monitorsToPages, page } from "@openstatus/db/src/schema";
import {
incident,
monitor,
monitorsToIncidents,
monitorsToPages,
page,
pagesToIncidents,
} from "@openstatus/db/src/schema";
import { getMonitorList, Tinybird } from "@openstatus/tinybird";
import { Redis } from "@openstatus/upstash";

Expand All @@ -20,6 +27,7 @@ enum Status {
MajorOutage = "major_outage",
UnderMaintenance = "under_maintenance",
Unknown = "unknown",
Incident = "incident",
}

export const status = new Hono();
Expand All @@ -33,17 +41,37 @@ status.get("/:slug", async (c) => {

return c.json({ status: cache });
}

startTime(c, "database");
// { monitors, pages, monitors_to_pages }
const monitorData = await db
.select()
.from(monitorsToPages)
.leftJoin(monitor, eq(monitorsToPages.monitorId, monitor.id))
.leftJoin(
monitorsToIncidents,
eq(monitor.id, monitorsToIncidents.monitorId),
)
.leftJoin(incident, eq(monitorsToIncidents.incidentId, incident.id))
.leftJoin(page, eq(monitorsToPages.pageId, page.id))
.where(eq(page.slug, slug))
.all();

const pageIncidentData = await db
.select()
.from(pagesToIncidents)
.leftJoin(incident, eq(pagesToIncidents.incidentId, incident.id))
.leftJoin(page, eq(pagesToIncidents.pageId, page.id))
.where(eq(page.slug, slug))
.all();

endTime(c, "database");

const isIncident = [...pageIncidentData, ...monitorData].some((data) => {
if (!data.incident) return false;
return !["monitoring", "resolved"].includes(data.incident.status);
});

startTime(c, "clickhouse");
// { data: [{ ok, count }] }
const lastMonitorPings = await Promise.allSettled(
Expand Down Expand Up @@ -77,7 +105,8 @@ status.get("/:slug", async (c) => {

const ratio = data.ok / data.count;

const status = getStatus(ratio);
const status: Status = isIncident ? Status.Incident : getStatus(ratio);

await redis.set(slug, status, { ex: 30 });

return c.json({ status });
Expand Down
3 changes: 2 additions & 1 deletion packages/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ export type Status =
| "partial_outage"
| "major_outage"
| "under_maintenance"
| "unknown";
| "unknown"
| "incident";
```

Learn more in the [docs](https://docs.openstatus.dev/packages/react).
Expand Down
11 changes: 10 additions & 1 deletion packages/react/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export const statusDictionary = {
import type { Status } from "./widget";

export const statusDictionary: Record<
Status,
{ label: string; color: string }
> = {
operational: {
label: "Operational",
color: "bg-green-500",
Expand All @@ -19,6 +24,10 @@ export const statusDictionary = {
label: "Unknown",
color: "bg-gray-500",
},
incident: {
label: "Incident",
color: "bg-yellow-500",
},
under_maintenance: {
label: "Under Maintenance",
color: "bg-gray-500",
Expand Down
10 changes: 5 additions & 5 deletions packages/react/src/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export type Status =
| "partial_outage"
| "major_outage"
| "under_maintenance"
| "unknown";
| "unknown"
| "incident";

export type StatusResponse = { status: Status };

Expand All @@ -29,10 +30,9 @@ export type StatusWidgetProps = {
};

export async function StatusWidget({ slug, href }: StatusWidgetProps) {
const data = await getStatus(slug);
const { status } = await getStatus(slug);

const key = data.status;
const { label, color } = statusDictionary[key];
const { label, color } = statusDictionary[status];

return (
<a
Expand All @@ -43,7 +43,7 @@ export async function StatusWidget({ slug, href }: StatusWidgetProps) {
>
{label}
<span className="relative flex h-2 w-2">
{data.status === "operational" ? (
{status === "operational" ? (
<span
className={`absolute inline-flex h-full w-full animate-ping rounded-full ${color} opacity-75 duration-1000`}
/>
Expand Down

0 comments on commit b999dd0

Please sign in to comment.