feat(ifc file importer): add healthcheck endpoint (#5232)

* Serve path `/healthz`
* Include readiness and startup probes
This commit is contained in:
Iain Sproat
2025-08-14 11:33:54 +01:00
committed by GitHub
parent 82caecb841
commit 4d8d93f75e
5 changed files with 78 additions and 9 deletions
@@ -14,7 +14,7 @@ export const startHealthCheckServer = (params: { logger: Logger }) => {
})
server.listen(9080, '0.0.0.0', () => {
logger.info('Server running, listening to 0.0.0.0 and path /healthz')
logger.info('Healthcheck server is running. Serving at 0.0.0.0:9080/healthz')
})
return server
+18
View File
@@ -1,6 +1,8 @@
import asyncio
import logging
import sys
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
import structlog
from structlog_to_seq import CelfProcessor
@@ -31,9 +33,25 @@ def configure_logger() -> structlog.stdlib.BoundLogger:
return logger
class HealthcheckHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self): # noqa: N802
match self.path:
case "/healthz":
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(b'{"status": "OK"}')
case _:
self.send_response(404)
self.end_headers()
async def main():
logger = configure_logger()
task = asyncio.create_task(job_processor(logger))
httpd = HTTPServer(("0.0.0.0", 9080), HealthcheckHTTPRequestHandler)
thread = threading.Thread(target=httpd.serve_forever, daemon=True)
thread.start()
# we do not need any sort of signal handling logic,
# cause if the context of the job transaction exits,
@@ -69,11 +69,13 @@ async def job_handler(
async def job_processor(logger: structlog.stdlib.BoundLogger):
parser = "speckle_ifc"
logger = logger.bind(parser=parser)
connection = await setup_connection()
logger.info("job processor started")
while True:
job = await get_next_job(connection)
if not job:
logger.info("no job found")
logger.debug("no job found")
await asyncio.sleep(IDLE_TIMEOUT)
continue
@@ -37,9 +37,42 @@ spec:
containerPort: 9093
protocol: TCP
startupProbe:
periodSeconds: 10
failureThreshold: 18 # 10 * 18 = 180s to startup
timeoutSeconds: 3
{{- if .Values.featureFlags.nextGenFileImporterEnabled }}
httpGet:
path: /healthz
port: 9080
{{- else }}
exec:
command:
- /usr/bin/node
- -e
- "process.exit((Date.now() - require('fs').readFileSync('/tmp/last_successful_query', 'utf8') > 25 * 60 * 1000) ? 1 : 0)"
{{- end }}
livenessProbe:
initialDelaySeconds: 60
periodSeconds: 60
timeoutSeconds: 3
{{- if .Values.featureFlags.nextGenFileImporterEnabled }}
httpGet:
path: /healthz
port: 9080
{{- else }}
exec:
command:
- /usr/bin/node
- -e
- "process.exit((Date.now() - require('fs').readFileSync('/tmp/last_successful_query', 'utf8') > 25 * 60 * 1000) ? 1 : 0)"
{{- end }}
readinessProbe:
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 3
{{- if .Values.featureFlags.nextGenFileImporterEnabled }}
httpGet:
path: /healthz
@@ -31,13 +31,29 @@ spec:
containerPort: 9093
protocol: TCP
# TODO: Enable health checks
# livenessProbe:
# initialDelaySeconds: 60
# periodSeconds: 60
# httpGet:
# path: /healthz
# port: 9080
startupProbe:
periodSeconds: 10
failureThreshold: 18 # 10 * 18 = 180s to startup
timeoutSeconds: 3
httpGet:
path: /healthz
port: 9080
livenessProbe:
initialDelaySeconds: 60
periodSeconds: 60
timeoutSeconds: 3
httpGet:
path: /healthz
port: 9080
readinessProbe:
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 3
httpGet:
path: /healthz
port: 9080
resources:
{{- with .Values.ifc_import_service.requests }}