+1
-1
apps/hosting-service/package.json
+1
-1
apps/hosting-service/package.json
+33
apps/hosting-service/src/lib/firehose.ts
+33
apps/hosting-service/src/lib/firehose.ts
···
20
20
private idResolver: IdResolver
21
21
private isShuttingDown = false
22
22
private lastEventTime = Date.now()
23
+
private eventCount = 0
23
24
private cacheCleanupInterval: NodeJS.Timeout | null = null
25
+
private healthCheckInterval: NodeJS.Timeout | null = null
24
26
25
27
constructor(
26
28
private logger?: (msg: string, data?: Record<string, unknown>) => void
···
47
49
48
50
this.log('IdResolver cache cleared')
49
51
}, 60 * 60 * 1000) // Every hour
52
+
53
+
// Health check: log if no events received for 30 seconds
54
+
this.healthCheckInterval = setInterval(() => {
55
+
if (this.isShuttingDown) return
56
+
57
+
const timeSinceLastEvent = Date.now() - this.lastEventTime
58
+
if (timeSinceLastEvent > 30000 && this.eventCount === 0) {
59
+
this.log('Warning: No firehose events received in the last 30 seconds', {
60
+
timeSinceLastEvent,
61
+
eventsReceived: this.eventCount
62
+
})
63
+
} else if (timeSinceLastEvent > 60000) {
64
+
this.log('Firehose status check', {
65
+
timeSinceLastEvent,
66
+
eventsReceived: this.eventCount
67
+
})
68
+
}
69
+
}, 30000) // Every 30 seconds
50
70
}
51
71
52
72
start() {
···
61
81
if (this.cacheCleanupInterval) {
62
82
clearInterval(this.cacheCleanupInterval)
63
83
this.cacheCleanupInterval = null
84
+
}
85
+
86
+
if (this.healthCheckInterval) {
87
+
clearInterval(this.healthCheckInterval)
88
+
this.healthCheckInterval = null
64
89
}
65
90
66
91
if (this.firehose) {
···
80
105
filterCollections: ['place.wisp.fs', 'place.wisp.settings'],
81
106
handleEvent: async (evt: any) => {
82
107
this.lastEventTime = Date.now()
108
+
this.eventCount++
109
+
110
+
if (this.eventCount === 1) {
111
+
this.log('First firehose event received - connection established', {
112
+
eventType: evt.event,
113
+
collection: evt.collection
114
+
})
115
+
}
83
116
84
117
// Watch for write events
85
118
if (evt.event === 'create' || evt.event === 'update') {
+1
apps/hosting-service/src/lib/storage.ts
+1
apps/hosting-service/src/lib/storage.ts
+2
-2
bun.lock
+2
-2
bun.lock
···
36
36
"mime-types": "^2.1.35",
37
37
"multiformats": "^13.4.1",
38
38
"postgres": "^3.4.5",
39
-
"tiered-storage": "1.0.1",
39
+
"tiered-storage": "1.0.3",
40
40
},
41
41
"devDependencies": {
42
42
"@types/bun": "^1.3.1",
···
1219
1219
1220
1220
"thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="],
1221
1221
1222
-
"tiered-storage": ["tiered-storage@1.0.1", "", { "dependencies": { "@aws-sdk/client-s3": "^3.500.0", "@aws-sdk/lib-storage": "^3.500.0", "hono": "^4.10.7", "mime-types": "^3.0.2", "tiny-lru": "^11.0.0" } }, "sha512-IHroV3iGDK2rSNiYEBpNj9RDyWSRYPiBRySxfaWOIgGvSlQBBSuv2cp5nifvPi0ep5pD/SXG3gan3EDv86GYrQ=="],
1222
+
"tiered-storage": ["tiered-storage@1.0.3", "", { "dependencies": { "@aws-sdk/client-s3": "^3.500.0", "@aws-sdk/lib-storage": "^3.500.0", "hono": "^4.10.7", "mime-types": "^3.0.2", "tiny-lru": "^11.0.0" } }, "sha512-ntJCsWWYHSQWIDbObMfnJ8xw7cRSJCPzfbrjoY4hu0YIRizCthRWg8kCvJOgsgC+Upt259YHmfNwEr1wLv6Rxw=="],
1223
1223
1224
1224
"tiny-lru": ["tiny-lru@11.4.5", "", {}, "sha512-hkcz3FjNJfKXjV4mjQ1OrXSLAehg8Hw+cEZclOVT+5c/cWQWImQ9wolzTjth+dmmDe++p3bme3fTxz6Q4Etsqw=="],
1225
1225