public uptime monitoring + (soon) observability with events saved to PDS
1import type { ServiceConfig, UptimeCheck } from './types.ts';
2
3/**
4 * performs an uptime check on a service
5 *
6 * @param service the service configuration
7 * @returns the uptime check result
8 */
9export async function checkService(service: ServiceConfig): Promise<UptimeCheck> {
10 const timeout = service.timeout || 5000;
11 const startTime = Date.now();
12 const checkedAt = new Date().toISOString();
13
14 try {
15 const controller = new AbortController();
16 const timeoutId = setTimeout(() => {
17 controller.abort();
18 }, timeout);
19
20 const headers: HeadersInit = {};
21 if (service.host) {
22 headers.Host = service.host;
23 }
24
25 const response = await fetch(service.url, {
26 method: 'GET',
27 signal: controller.signal,
28 redirect: 'follow',
29 headers,
30 });
31
32 clearTimeout(timeoutId);
33
34 const responseTime = Date.now() - startTime;
35
36 return {
37 ...(service.group && { groupName: service.group }),
38 serviceName: service.name,
39 ...(service.region && { region: service.region }),
40 serviceUrl: service.url,
41 checkedAt,
42 status: 'up',
43 responseTime,
44 httpStatus: response.status,
45 };
46 } catch (error) {
47 const responseTime = Date.now() - startTime;
48 let errorMessage = 'unknown error';
49
50 if (error instanceof Error) {
51 if (error.name === 'AbortError') {
52 errorMessage = `timeout after ${timeout}ms`;
53 } else {
54 errorMessage = error.message;
55 }
56 }
57
58 return {
59 ...(service.group && { groupName: service.group }),
60 serviceName: service.name,
61 ...(service.region && { region: service.region }),
62 serviceUrl: service.url,
63 checkedAt,
64 status: 'down',
65 responseTime: -1,
66 errorMessage,
67 };
68 }
69}