Monitoring & Performance
Section titled “Monitoring & Performance”The hoody-exec monitoring endpoints expose runtime health, request activity, per-script performance, and process control for a single exec instance. Use them to power dashboards, alert on error rates or stalled requests, integrate with Prometheus, or coordinate safe restarts. Script identifiers (scriptPath) are returned relative to the container’s scripts root, so a script at /hoody/storage/hoody-exec/scripts/default/1/checkout.ts is exposed as default/1/checkout.ts in every response except GET /api/v1/exec/system/restart-status, whose active array surfaces the absolute filesystem path.
All endpoints target the exec service on the container’s per-instance hostname.
Health
Section titled “Health”GET /api/v1/exec/health
Section titled “GET /api/v1/exec/health”Returns the exec service liveness state, process identity, and resource snapshot. Kubernetes-style probes commonly target this endpoint because the response is small, has no side effects, and reflects the actual Node process.
This endpoint takes no parameters.
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/health" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.health.check();{ "status": "ok", "service": "hoody-exec", "built": "2026-01-15T08:30:00.000Z", "started": "2026-01-20T14:22:11.481Z", "memory": { "rss": 84323144, "heap": 41234560 }, "fds": 28, "pid": 417, "ip": "10.0.4.7", "userAgent": "kube-probe/1.29"}{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "headers", "reason": "missing required header" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}Monitor
Section titled “Monitor”GET /api/v1/exec/monitor/active-requests
Section titled “GET /api/v1/exec/monitor/active-requests”Lists every script HTTP request currently in flight, including the resolved execution ID, originating client IP, request method and URL, and elapsed time. Use this to spot stuck handlers or to drive a live activity dashboard.
This endpoint takes no parameters.
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/monitor/active-requests" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.monitor.getActiveRequests();{ "count": 2, "active": [ { "executionId": "01HQX2P3K9N4M8R7T6V1Y0ABC5", "scriptPath": "default/1/checkout.ts", "hostname": "checkout-svc", "clientIp": "203.0.113.42", "method": "POST", "url": "/api/checkout", "startedAt": "2026-01-20T14:22:11.481Z", "duration": 432 }, { "executionId": "01HQX2P3K9N4M8R7T6V1Y0DEF8", "scriptPath": "default/1/webhook-stripe.ts", "hostname": "stripe-webhook", "clientIp": "54.187.205.235", "method": "POST", "url": "/hooks/stripe", "startedAt": "2026-01-20T14:22:09.117Z", "duration": 2815 } ]}{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "headers", "reason": "missing required header" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}GET /api/v1/exec/monitor/metrics
Section titled “GET /api/v1/exec/monitor/metrics”Returns the Prometheus 0.0.4 text exposition format for scraping. Counters and histograms expose request totals, errors, per-script and aggregate request-duration distributions, WebSocket open/close counts, and process start time. Returns 404 when the server was started with --prometheus off.
This endpoint takes no parameters.
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/monitor/metrics" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.monitor.prometheusExport();# HELP hoody_exec_http_requests_total Total HTTP script requests handled# TYPE hoody_exec_http_requests_total counterhoody_exec_http_requests_total{script="default/1/checkout.ts"} 1247hoody_exec_http_requests_total{script="default/1/webhook-stripe.ts"} 312# HELP hoody_exec_http_errors_total Total HTTP script errors# TYPE hoody_exec_http_errors_total counterhoody_exec_http_errors_total{script="default/1/checkout.ts"} 4hoody_exec_http_errors_total{script="default/1/webhook-stripe.ts"} 1# HELP hoody_exec_http_duration_ms HTTP request duration in milliseconds (per script)# TYPE hoody_exec_http_duration_ms histogramhoody_exec_http_duration_ms_bucket{script="default/1/checkout.ts",le="50"} 12hoody_exec_http_duration_ms_bucket{script="default/1/checkout.ts",le="200"} 612hoody_exec_http_duration_ms_bucket{script="default/1/checkout.ts",le="+Inf"} 1247hoody_exec_http_duration_ms_sum{script="default/1/checkout.ts"} 389531.2hoody_exec_http_duration_ms_count{script="default/1/checkout.ts"} 1247# HELP hoody_exec_http_duration_ms_global HTTP request duration in milliseconds (aggregate)# TYPE hoody_exec_http_duration_ms_global histogramhoody_exec_http_duration_ms_global_bucket{le="50"} 80hoody_exec_http_duration_ms_global_bucket{le="200"} 1142hoody_exec_http_duration_ms_global_bucket{le="+Inf"} 1559hoody_exec_http_duration_ms_global_sum 524812.4hoody_exec_http_duration_ms_global_count 1559# HELP hoody_exec_ws_connections_active Active WebSocket connections# TYPE hoody_exec_ws_connections_active gaugehoody_exec_ws_connections_active 23# HELP hoody_exec_ws_closes_total Total WebSocket closes# TYPE hoody_exec_ws_closes_total counterhoody_exec_ws_closes_total{reason="normal"} 4760hoody_exec_ws_closes_total{reason="abnormal"} 38# HELP hoody_exec_metrics_errors_total Metrics registry internal errors# TYPE hoody_exec_metrics_errors_total counterhoody_exec_metrics_errors_total 0# HELP process_start_time_seconds Process start time# TYPE process_start_time_seconds gaugeprocess_start_time_seconds 1737381731.481{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "headers", "reason": "missing required header" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
# Prometheus metrics disabled (server started with --prometheus off){ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}GET /api/v1/exec/monitor/scripts
Section titled “GET /api/v1/exec/monitor/scripts”Lists every tracked script with lifetime HTTP and WebSocket metrics, recent errors, and VM-cache state. Use sort to rank by error rate or latency instead of recency.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | No | Max number of scripts to return. Clamped to [1, 500]. Default: 100. |
sort | query | string | No | Sort key. lastActivity (default) sorts by most recent activity; other keys sort descending by the matching metric. One of: lastActivity, requests, errors, p95, ws_active. Default: "lastActivity". |
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/monitor/scripts?limit=50&sort=p95" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.monitor.listMonitorScripts({ limit: 50, sort: 'p95' });{ "count": 2, "total": 18, "scripts": [ { "scriptPath": "default/1/checkout.ts", "hostname": "checkout-svc", "vmCached": true, "sharedStateBytes": 4192, "activeHttp": 2, "activeWs": 0, "concurrentRunning": 1, "http": { "total": 1247, "success": 1243, "errors": 4, "meanDurationMs": 312.4, "p50DurationMs": 198, "p95DurationMs": 821, "maxDurationMs": 1843 }, "ws": { "opened": 0, "closed": 0, "normalCloses": 0, "abnormalCloses": 0, "meanSessionMs": 0, "maxSessionMs": 0 }, "recentErrors": [ { "timestamp": "2026-01-20T14:18:02.114Z", "statusCode": 500, "message": "Stripe API timeout after 3000ms", "executionId": "01HQX2M9R4N7K1V8P3T6Y0XJC2" } ], "firstSeenAt": "2025-11-04T09:12:00.000Z", "lastActivityAt": "2026-01-20T14:22:09.117Z" }, { "scriptPath": "default/1/webhook-stripe.ts", "hostname": "stripe-webhook", "vmCached": true, "sharedStateBytes": null, "activeHttp": 1, "activeWs": 23, "concurrentRunning": 1, "http": { "total": 312, "success": 309, "errors": 3, "meanDurationMs": 412.8, "p50DurationMs": 287, "p95DurationMs": 1203, "maxDurationMs": 2411 }, "ws": { "opened": 4821, "closed": 4798, "normalCloses": 4760, "abnormalCloses": 38, "meanSessionMs": 18523, "maxSessionMs": 148203 }, "recentErrors": [], "firstSeenAt": "2025-11-04T09:12:00.000Z", "lastActivityAt": "2026-01-20T14:22:11.481Z" } ]}{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "limit", "reason": "must be between 1 and 500" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}GET /api/v1/exec/monitor/stats
Section titled “GET /api/v1/exec/monitor/stats”Returns a single aggregate snapshot of the process: uptime, memory, cache sizes, request counters, rolling req/s averages, WebSocket state, cron counters, and any dropped-script count from the LRU map. The cron.active and cron.wrapperActive gap indicates soft-timeout-orphaned work still in the VM.
This endpoint takes no parameters.
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/monitor/stats" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.monitor.getStats();{ "uptime": 86420, "memory": { "used": 61234560, "total": 134217728, "percentage": 45.6, "rss": 84323144, "external": 1048576 }, "cache": { "scripts": 18, "vms": 6, "sharedStates": 3, "activeWsHostnames": 2 }, "requests": { "total": 149823, "success": 149211, "errors": 612, "activeHttp": 4, "perSecond": 1.73, "per1m": 4.2, "per5m": 5.1, "per15m": 6.8 }, "websocket": { "opened": 4821, "closed": 4798, "active": 23, "normalCloses": 4760, "abnormalCloses": 38 }, "cron": { "fires": 1440, "errors": 3, "active": 0, "wrapperActive": 0 }, "droppedScripts": 0, "sinceMs": 1737381731000}{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "headers", "reason": "missing required header" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}POST /api/v1/exec/monitor/script-performance
Section titled “POST /api/v1/exec/monitor/script-performance”Returns the lifetime metrics object for a tracked script. When the script is not tracked, metrics is the empty object {}.
This endpoint takes no path, query, or header parameters.
curl -X POST "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/monitor/script-performance" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.monitor.getScriptPerformance({});{ "metrics": { "scriptPath": "default/1/checkout.ts", "period": "lifetime", "http": { "total": 1247, "success": 1243, "errors": 4, "meanDurationMs": 312.4, "p50DurationMs": 198, "p95DurationMs": 821, "maxDurationMs": 1843, "recentDurationsMs": [412, 198, 287, 821, 104, 312, 642, 251] }, "ws": { "opened": 0, "closed": 0, "normalCloses": 0, "abnormalCloses": 0, "meanSessionMs": 0, "maxSessionMs": 0 }, "activeHttp": 2, "activeWs": 0, "firstSeenAt": "2025-11-04T09:12:00.000Z", "lastActivityAt": "2026-01-20T14:22:09.117Z" }}{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "headers", "reason": "missing required header" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}System
Section titled “System”GET /api/v1/exec/system/restart-status
Section titled “GET /api/v1/exec/system/restart-status”Reports whether the exec instance can be safely restarted right now. restartReady is true only when no in-flight HTTP requests remain. Unlike the other monitor endpoints, the active array here returns absolute filesystem paths so an operator can correlate live work to a file on disk.
This endpoint takes no parameters.
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/system/restart-status" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.exec.system.getRestartStatus();{ "canRestart": false, "uptime": 86420, "uptimeFormatted": "1d 0h 0m 20s", "activeRequests": 2, "active": [ { "scriptPath": "/hoody/storage/hoody-exec/scripts/default/1/checkout.ts" }, { "scriptPath": "/hoody/storage/hoody-exec/scripts/default/1/webhook-stripe.ts" } ], "restartReady": false}{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "headers", "reason": "missing required header" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}POST /api/v1/exec/system/restart
Section titled “POST /api/v1/exec/system/restart”Triggers a graceful restart of the exec process. Defaults are tuned for safe in-flight drain: 5 seconds of grace for active HTTP handlers, with the reason recorded in the server log. Use after deploying a new script bundle or rotating shared state.
This endpoint takes no path, query, or header parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
graceful | boolean | No | true | Drain in-flight requests before exiting. |
drainTimeoutMs | integer | No | 5000 | Max milliseconds to wait for in-flight requests to finish before forcing exit. |
reason | string | No | "API restart request" | Operator-supplied reason written to the server log. |
curl -X POST "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/system/restart" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{ "graceful": true, "drainTimeoutMs": 8000, "reason": "deploying script bundle v2.4.1" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.exec.system.restartServer({ graceful: true, drainTimeoutMs: 8000, reason: 'deploying script bundle v2.4.1' });{ "error": "Invalid parameter format", "code": "VALIDATION_ERROR", "timestamp": "2026-01-20T14:22:11.481Z", "details": { "field": "drainTimeoutMs", "reason": "must be a non-negative integer" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input | Request parameters failed validation | Check parameter format and requirements |
{ "error": "Internal server error", "code": "ERROR_500", "timestamp": "2026-01-20T14:22:11.481Z", "details": {}}