add-a-simple-health-endpoint-to-the-api: add GET /health endpoint#617
Conversation
- Added HealthServerService that starts a lightweight HTTP server on port 3456 - GET /health returns 200 with JSON: status, name, version, timestamp - Server starts on extension activation and stops on deactivation - Non-fatal: port conflicts are logged as warnings without blocking activation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughA new HealthServerService is introduced to expose a lightweight HTTP /health endpoint returning extension status, name, version, and timestamp. The service is integrated into the extension's activation and deactivation lifecycle, starting on activation and stopping on deactivation with graceful error handling for non-fatal port conflicts. Changes
Sequence DiagramsequenceDiagram
participant Ext as Extension<br/>(Activation)
participant HS as HealthServerService
participant Server as HTTP Server
participant Client as Health Check<br/>Client
Ext->>HS: new HealthServerService(name, version, port)
Ext->>HS: start()
HS->>Server: http.createServer()
HS->>Server: listen(port)
Server->>HS: listening event
HS->>Ext: Promise resolved
Client->>Server: GET /health
Server->>HS: handleRequest()
HS->>HS: handleHealth()
HS->>Client: 200 JSON {status, name, version, timestamp}
Ext->>HS: stop()
HS->>Server: close()
Server->>HS: closed
HS->>Ext: Promise resolved
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/extension/services/health-server-service.ts (1)
125-141: Consider reducing log verbosity for health checks.Line 140 logs every health check request at INFO level. If monitoring tools poll frequently (e.g., every 5-10 seconds), this will generate significant log noise.
Consider either removing this log, changing it to DEBUG level (if available), or rate-limiting the log output.
🔧 Suggested fix to reduce log verbosity
res.end(json); - - log('INFO', 'Health check request served'); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/extension/services/health-server-service.ts` around lines 125 - 141, The health-check handler handleHealth currently logs every request with log('INFO', ...) causing noise; reduce verbosity by either removing that log call or lowering it to a debug level (e.g., log('DEBUG', ...)) and, if your logger supports it, wrap it with a guard like isDebugEnabled() before calling; alternatively implement simple rate-limiting/throttling around the log invocation (track lastLogged timestamp inside the HealthServerService) so handleHealth only emits a log at most once per configurable interval.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/extension/extension.ts`:
- Around line 244-254: The deactivate() function currently returns void while
calling the async healthServer?.stop() fire-and-forget; change deactivate to
return a Thenable<void> (or async Promise<void>) so you can await
healthServer.stop() before disposing resources: call and await (or return)
healthServer.stop() (handling rejection and logging the error with the
still-open outputChannel), only then call outputChannel?.dispose() and null
assignments; reference the deactivate function and healthServer.stop() and
outputChannel.dispose() when making the change and ensure you propagate the
stop() promise (or use Promise.resolve/Promise.all if adding other async
cleanup) so VS Code can wait for clean shutdown.
---
Nitpick comments:
In `@src/extension/services/health-server-service.ts`:
- Around line 125-141: The health-check handler handleHealth currently logs
every request with log('INFO', ...) causing noise; reduce verbosity by either
removing that log call or lowering it to a debug level (e.g., log('DEBUG', ...))
and, if your logger supports it, wrap it with a guard like isDebugEnabled()
before calling; alternatively implement simple rate-limiting/throttling around
the log invocation (track lastLogged timestamp inside the HealthServerService)
so handleHealth only emits a log at most once per configurable interval.
| export function deactivate(): void { | ||
| log('INFO', 'Claude Code Workflow Studio is now deactivated'); | ||
|
|
||
| // Stop health server if running | ||
| healthServer?.stop().catch((err: Error) => { | ||
| log('WARN', 'Health server failed to stop cleanly', { error: err.message }); | ||
| }); | ||
| healthServer = null; | ||
|
|
||
| outputChannel?.dispose(); | ||
| outputChannel = null; |
There was a problem hiding this comment.
Async cleanup may not complete before extension fully deactivates.
The deactivate() function returns void but healthServer?.stop() is async. VS Code supports returning Thenable<void> from deactivate() to allow proper async cleanup. Currently:
- The stop() promise is fire-and-forget
outputChannel?.dispose()may execute before the server finishes stopping- Any logs from stop() could fail if outputChannel is already disposed
Consider returning the promise to ensure clean shutdown.
🔧 Suggested fix for proper async cleanup
/**
* Extension deactivation function
* Called when the extension is deactivated
*/
-export function deactivate(): void {
+export async function deactivate(): Promise<void> {
log('INFO', 'Claude Code Workflow Studio is now deactivated');
// Stop health server if running
- healthServer?.stop().catch((err: Error) => {
- log('WARN', 'Health server failed to stop cleanly', { error: err.message });
- });
+ if (healthServer) {
+ try {
+ await healthServer.stop();
+ } catch (err) {
+ log('WARN', 'Health server failed to stop cleanly', {
+ error: err instanceof Error ? err.message : String(err)
+ });
+ }
+ }
healthServer = null;
outputChannel?.dispose();
outputChannel = null;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/extension/extension.ts` around lines 244 - 254, The deactivate() function
currently returns void while calling the async healthServer?.stop()
fire-and-forget; change deactivate to return a Thenable<void> (or async
Promise<void>) so you can await healthServer.stop() before disposing resources:
call and await (or return) healthServer.stop() (handling rejection and logging
the error with the still-open outputChannel), only then call
outputChannel?.dispose() and null assignments; reference the deactivate function
and healthServer.stop() and outputChannel.dispose() when making the change and
ensure you propagate the stop() promise (or use Promise.resolve/Promise.all if
adding other async cleanup) so VS Code can wait for clean shutdown.
|
Thanks for the PR! Before diving into a full review, a couple of questions:
Thanks! |
Summary
HealthServerService(src/extension/services/health-server-service.ts) that starts a lightweight Node.js HTTP server on port 3456 when the extension activatesGET /healthreturns HTTP 200 with a JSON body:{ status, name, version, timestamp }extension.tsafter all commands are registered (fire-and-forget, non-fatal on port conflicts)deactivate()Example response
```json
{
"status": "ok",
"name": "cc-wf-studio",
"version": "3.12.3",
"timestamp": "2026-02-28T10:00:00.000Z"
}
```
Test plan
curl http://127.0.0.1:3456/health— expect200 OKwith JSON bodycurl http://127.0.0.1:3456/) — expect404 Not Foundnpm run format && npm run lint && npm run check && npm run build:extension🤖 Generated with Claude Code
Summary by CodeRabbit