Skip to content

Commit dffe2a0

Browse files
authored
feat: Add watchdog and healthcheck (#22)
1 parent 021620d commit dffe2a0

File tree

4 files changed

+55
-2
lines changed

4 files changed

+55
-2
lines changed

Dockerfile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,15 @@ RUN mkdir -p /app/config
4343

4444
# Set environment variables
4545
ENV CONFIG_PATH=/app/config/config.json \
46-
CERT_PATH=/app/certs
46+
CERT_PATH=/app/certs \
47+
NODE_ENV=production
48+
49+
# Expose health check port
50+
EXPOSE 8080
51+
52+
# Add health check
53+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
54+
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
4755

4856
# Run the application
4957
CMD ["node", "dist/forwarder.js"]

hassio-addon/config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ startup: application
1313
boot: auto
1414
services:
1515
- mqtt:need
16+
watchdog: "http://[HOST]:[PORT:8080]/health"
1617
options:
1718
inverse_forwarding: false
1819
devices:

src/forwarder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import {readFileSync} from 'fs';
44
import {join} from 'path';
55
import {createHash} from 'crypto';
66
import fetch from 'node-fetch';
7+
import { HealthServer } from './health';
78

8-
const deviceGenerations = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] as const;
9+
const deviceGenerations = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 50] as const;
910
type DeviceGen = typeof deviceGenerations[number];
1011
const deviceTypes = ["A", "B", "D", "E", "F", "G", "J", "K"] as const;
1112
type DeviceType = typeof deviceTypes[number];
@@ -149,6 +150,7 @@ function cleanAndValidate(config: Config): void {
149150
class MQTTForwarder {
150151
private configBroker!: mqtt.MqttClient;
151152
private hameBroker!: mqtt.MqttClient;
153+
private healthServer!: HealthServer;
152154
private readonly MESSAGE_HISTORY_TIMEOUT = 1000; // 1 second timeout
153155
private readonly RATE_LIMIT_INTERVAL = 59900; // Rate limit interval in milliseconds
154156
private readonly MESSAGE_CACHE_TIMEOUT = 1000; // 1 second timeout for message loop prevention
@@ -161,6 +163,8 @@ class MQTTForwarder {
161163
constructor(private readonly config: Config) {
162164
// Initialize brokers
163165
this.initializeBrokers();
166+
// Initialize health server
167+
this.healthServer = new HealthServer(this.configBroker, this.hameBroker);
164168
}
165169

166170
/**
@@ -429,6 +433,7 @@ class MQTTForwarder {
429433
public close(): void {
430434
this.configBroker.end();
431435
this.hameBroker.end();
436+
this.healthServer.close();
432437
}
433438

434439
// Clean up old message history entries periodically

src/health.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { createServer, IncomingMessage, ServerResponse } from 'http';
2+
import { MqttClient } from 'mqtt';
3+
4+
export class HealthServer {
5+
private server: ReturnType<typeof createServer>;
6+
private configBroker: MqttClient;
7+
private hameBroker: MqttClient;
8+
9+
constructor(configBroker: MqttClient, hameBroker: MqttClient, port: number = 8080) {
10+
this.configBroker = configBroker;
11+
this.hameBroker = hameBroker;
12+
13+
this.server = createServer(this.handleRequest.bind(this));
14+
this.server.listen(port, () => {
15+
console.log(`Health server listening on port ${port}`);
16+
});
17+
}
18+
19+
private handleRequest(req: IncomingMessage, res: ServerResponse): void {
20+
if (req.url === '/health' && req.method === 'GET') {
21+
const status = {
22+
status: 'ok',
23+
configBroker: this.configBroker.connected,
24+
hameBroker: this.hameBroker.connected,
25+
timestamp: new Date().toISOString()
26+
};
27+
28+
res.writeHead(200, { 'Content-Type': 'application/json' });
29+
res.end(JSON.stringify(status));
30+
} else {
31+
res.writeHead(404);
32+
res.end();
33+
}
34+
}
35+
36+
public close(): void {
37+
this.server.close();
38+
}
39+
}

0 commit comments

Comments
 (0)