Skip to content

Phase 8a-1: migrate health server to ASP.NET Core / Kestrel#14

Merged
JacobHaig merged 3 commits into
mainfrom
feat/file-relay-kestrel
Jun 2, 2026
Merged

Phase 8a-1: migrate health server to ASP.NET Core / Kestrel#14
JacobHaig merged 3 commits into
mainfrom
feat/file-relay-kestrel

Conversation

@JacobHaig
Copy link
Copy Markdown
Member

Phase 8a-1 — Kestrel foundation for the file-relay feature

First sub-phase of Phase 8 (the /upload file relay, plan §9). Lays the web foundation by moving off HttpListener; no behavior change to /health.

Changes

  • Wisbot.csproj — add <FrameworkReference Include="Microsoft.AspNetCore.App" /> (the supported way for a console app to host Kestrel).
  • Services/WebService.cs (replaces HealthService.cs) — Kestrel WebApplication minimal API; GET /health returns the same JSON (status, uptimeSeconds, latencyMs, guilds) with 200 (connected) / 503 (starting). Bind host +/* → all interfaces (container); localhost for dev. Ready to host the upload/download endpoints next.
  • Bot.cswebService = new WebService(...); await webService.Start() in StartBot.
  • Dockerfile — runtime base dotnet/runtime:10.0dotnet/aspnet:10.0.
  • CLAUDE.md updated.

Why now

Kestrel is the prerequisite for real web serving (multipart upload, 500MB streaming, routes) that HttpListener is poorly suited to. Doing it as an isolated, behavior-preserving step keeps the diff reviewable.

Verification

  • dotnet build — succeeds, 0 warnings, 0 errors.
  • The docker-build CI on this PR validates the new aspnet image builds.
  • Full /health runtime check happens in the container/deploy (as in Phase 2/3) — it requires a Discord token to reach WebService.Start().

Next: 8a-2 (/upload command + uploads DB schema + link minting), then 8a-3 (MinIO + streamed upload/download).

Phase 8a-1 of the file-relay feature (foundation for the upload/download web
endpoints). No behavior change to /health — same JSON + status codes.

- Add Microsoft.AspNetCore.App FrameworkReference (console app hosts Kestrel).
- Replace HttpListener HealthService with a Kestrel WebService (WebApplication
  minimal API); maps GET /health (200 connected / 503 starting). Bind host '+'/'*'
  -> all interfaces for the container; 'localhost' for dev.
- Dockerfile runtime base dotnet/runtime -> dotnet/aspnet (ASP.NET Core runtime).
- Update CLAUDE.md.

Next (8a-2): /upload slash command + uploads DB schema + link minting.
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, reopen this pull request to trigger a review.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: afed80ab-4de6-4f39-a669-f9822ca6f30c

📥 Commits

Reviewing files that changed from the base of the PR and between 37ca994 and b6aa81d.

📒 Files selected for processing (1)
  • Services/WebService.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • Services/WebService.cs

📝 Walkthrough

Summary by CodeRabbit

  • Infrastructure & Deployment
    • Health check endpoint migrated to modernized runtime architecture with all existing functionality preserved
    • Continues to monitor and report gateway connection status, uptime, latency, and guild information
    • Updated Docker base image deployment for improved runtime stability and long-term compatibility

Walkthrough

Replaces the custom HttpListener-based HealthService with an ASP.NET Core Kestrel WebService started from Bot.StartBot; adds Microsoft.AspNetCore.App framework reference, switches Docker runtime to aspnet:10.0, and updates docs to describe the new WebService and image/runtime details.

Changes

HealthService → WebService Migration

Layer / File(s) Summary
WebService implementation and ASP.NET Core integration
Services/WebService.cs, Wisbot.csproj
WebService hosts a Kestrel WebApplication bound to configured health host/port, implements Start() and Stop(), maps GET /health to return JSON (status, uptimeSeconds, latencyMs, guilds) with 200/503 based on Discord connection state, and project adds Microsoft.AspNetCore.App framework reference.
Bot service initialization and startup
Bot.cs
Bot replaces the HealthService field with a nullable WebService, constructs it in StartBot(), and calls webService.Start() during startup orchestration.
Docker runtime and documentation
Dockerfile, CLAUDE.md
Docker runtime base switches to mcr.microsoft.com/dotnet/aspnet:10.0. Documentation updated to describe the multi-stage build using aspnet, Kestrel-based /health binding via env vars, runtime-only configuration, Phase 8 endpoints, and native dependency handling (opus via apt, libsodium/SQLite via NuGet).

Sequence Diagram(s)

sequenceDiagram
  participant Bot
  participant WebService
  participant WebApp
  participant HealthEndpoint
  participant DiscordClient
  participant Client
  Bot->>WebService: Start()
  WebService->>WebApp: Build and configure host binding
  WebService->>WebApp: StartAsync()
  Client->>HealthEndpoint: GET /health
  HealthEndpoint->>DiscordClient: Read connection state and metrics
  HealthEndpoint-->>Client: Return JSON with 200 or 503
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • uhstray-io/WisBot#10: Introduced the original HttpListener-based HealthService implementation that this PR replaces with an ASP.NET Core WebService.

Poem

🐰 I hopped from listener to Kestrel's light,
/health now hums in JSON bright.
Docker dons aspnet, ports set free,
A rabbit cheers the web and gateway be.
🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: migrating the health server from HttpListener to ASP.NET Core/Kestrel.
Description check ✅ Passed The description is directly related to the changeset, providing context, rationale, and implementation details for the Kestrel migration across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/file-relay-kestrel

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Services/WebService.cs`:
- Around line 23-42: The Start method's catch currently only logs a warning and
nulls out app, leaving failures silent to orchestrators; update the Start method
(in class/method Start) to escalate startup bind/start errors: log at Error with
exception details and then fail fast by either rethrowing the exception or
terminating the process (e.g., set nonzero exit code / Environment.Exit) so
misconfiguration is observable; keep ConsoleLifetime behavior unchanged (do not
attempt to suppress it).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 249e89e0-db9f-4c71-a8d3-dcee20a2958d

📥 Commits

Reviewing files that changed from the base of the PR and between 12539a9 and 37ca994.

📒 Files selected for processing (6)
  • Bot.cs
  • CLAUDE.md
  • Dockerfile
  • Services/HealthService.cs
  • Services/WebService.cs
  • Wisbot.csproj
💤 Files with no reviewable changes (1)
  • Services/HealthService.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (3)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use the field keyword for properties with logic to avoid manual backing fields in C# 14

Use null-conditional assignment operator ?.= for defensive assignments

Use the new extension keyword for grouping extension members (properties, methods, and static members)

Use primary constructors for classes and structs unless complex initialization logic is required

Always use [] collection expression syntax for empty or populated collections/spans in C# 14

Use file-scoped namespaces with namespace MyProject.Models; syntax (no curly braces)

Rely on implicit usings and do not include standard system imports unless unique

Use var keyword only when the type is obvious from the right side of the assignment; use explicit types for method returns or literals

Use expression-bodied members with => for simple one-line methods and properties

Prefer ReadOnlySpan<char> for string parsing and slicing to optimize performance

Use the required keyword for properties that must be initialized via object initializers

Use raw string literals with """ for multi-line strings or JSON to avoid escaping quotes

Use PascalCase for Classes, Methods, Properties, and Public Fields

Use camelCase for local variables and method arguments

Avoid underscore prefixes for private fields (use the field keyword or this. prefix if absolutely necessary)

Use Task.Run() fire-and-forget pattern after immediate RespondAsync() followed by FollowupAsync() for long Discord operations to avoid 3-second interaction timeout

Use ConcurrentDictionary and ConcurrentQueue for thread-safe data structures; use lock for background service lists

All configuration settings must resolve via Config.Load() from environment variable, local .env file, or default—never hardcode site-specific values

Files:

  • Services/WebService.cs
  • Bot.cs
Services/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use manual constructor Dependency Injection without a DI container

Each service should live in its own file under Services/ directory with Bot.cs owning instances and wiring events

Files:

  • Services/WebService.cs
Bot.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Register slash commands idempotently on OnReady by checking if they already exist before creating

Files:

  • Bot.cs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T13:44:10.404Z
Learning: Use `dotnet build` to validate changes after completing modifications
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T13:44:10.404Z
Learning: Ensure code is well-structured, follows best practices, and includes appropriate error handling when making changes
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T13:44:10.404Z
Learning: Update CLAUDE.md and/or README.md after completing changes to reflect modifications and provide clear documentation
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T13:44:10.404Z
Learning: Read `.claude/memory/MEMORY.md` at the start of every session to load project context
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T13:44:10.404Z
Learning: Use `.claude/memory/` for storing architectural decisions, team conventions, external references, and domain knowledge
🔇 Additional comments (6)
Dockerfile (1)

15-15: LGTM!

CLAUDE.md (2)

18-18: LGTM!


41-41: LGTM!

Services/WebService.cs (1)

48-59: LGTM!

Wisbot.csproj (1)

9-14: LGTM!

Bot.cs (1)

18-18: LGTM!

Also applies to: 34-34, 46-46

Comment thread Services/WebService.cs
JacobHaig added 2 commits June 2, 2026 09:54
Register a no-op IHostLifetime so the embedded web host doesn't grab SIGINT/
SIGTERM or drive process shutdown — the bot process (Program.cs) owns the
lifetime. Prevents the web host's ConsoleLifetime from interfering with the
bot's signal handling in the container.
Escalate the start-failure log Warn -> Error and rethrow, so a bind failure
propagates to StartBot/Program (fatal exit) instead of silently running without
the health/upload endpoint. The web endpoint is now essential to the service.
@JacobHaig
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@JacobHaig JacobHaig merged commit 3f09afc into main Jun 2, 2026
2 checks passed
@JacobHaig JacobHaig deleted the feat/file-relay-kestrel branch June 2, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant