Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions critterwatch/WebService.Http/CritterWatchConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,18 @@
builder.Services.AddWolverineHttp();

// The console can also push operator commands (PauseProjection / RebuildProjection / DLQ ops / …) BACK to
// the OrderService over the same HTTP transport. Sending over the transport needs the transport client;
// register it so those sends work when an operator triggers them. (The named HttpClient that targets a
// specific service's control URL is created on demand from the service's reported control URI.)
// the OrderService over the same HTTP transport. Sending over the transport needs the transport client.
//
// ⚠️ On WolverineFx 6.23.1 (the pin below) this registration is NOT sufficient, and the control channel
// does not work. An earlier version of this comment claimed the named HttpClient for a service's control
// URL is "created on demand from the service's reported control URI" — it is not, and nothing creates it.
// WolverineHttpTransportClient uses the outbound URI purely as an IHttpClientFactory client NAME and then
// posts to that client's BaseAddress; CreateClient returns a default client with a null BaseAddress for an
// unknown name, so the send throws "An invalid request URI was provided…". The console cannot pre-register
// a named client either, because it only learns a service's control URL at runtime from that service's own
// registration. Reported as ProductSupport#34, fixed in wolverine#3681 (GH-3690): the transport falls back
// to its own isolated client and posts to the absolute outbound URI, and AddWolverineHttp() registers both
// of these lines for you. DELETE THEM when this sample bumps past that Wolverine release.
builder.Services.AddScoped<IWolverineHttpTransportClient, WolverineHttpTransportClient>();
builder.Services.AddHttpClient();

Expand Down
13 changes: 13 additions & 0 deletions critterwatch/WebService.Http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ receiver's HTTP endpoint.)
`IHttpClientFactory.CreateClient(outboundUri)` and POSTs to `client.BaseAddress`).
- `MapWolverineHttpTransportEndpoints()` so the console can POST operator commands **back** to this service.

> ⚠️ **The control channel (console → service) does not work on WolverineFx 6.23.1.** Telemetry
> (service → console) is fine. The send side resolves its `HttpClient` by using the outbound URI as an
> `IHttpClientFactory` client *name* and then posts to that client's `BaseAddress`; for a name nobody
> registered, `CreateClient` returns a default client whose `BaseAddress` is `null`, and the send throws
> `"An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress
> must be set."` The console **cannot** work around it — it only learns a service's control URL at runtime
> from that service's own registration, so there is no point at which it could register a named client.
>
> Reported as ProductSupport#34, fixed in wolverine#3681 (GH-3690). When this sample bumps past that
> release: delete the two manual registration lines in `CritterWatchConsole/Program.cs`
> (`AddWolverineHttp()` registers them), and un-skip
> `WebServiceHttpSmokeTests.console_control_channel_sends_without_transport_errors`.

**CritterWatchConsole (receiver)** — `CritterWatchConsole/Program.cs`:
- `AddCritterWatch(...)` for the dashboard/store, then `app.MapWolverineHttpTransportEndpoints()` to receive
envelopes at `/_wolverine/invoke`, executed inline against the console's CritterWatch handlers.
Expand Down
38 changes: 38 additions & 0 deletions critterwatch/WebService.Http/Tests/WebServiceHttpSmokeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,42 @@ public async Task order_service_registers_with_the_console_over_http_transport()

services.Select(s => s.Id).ShouldContain("OrderService");
}

/// <summary>
/// The CONTROL direction of the monitoring link — console → service — which this battery never
/// covered. Everything above exercises telemetry (service → console), which is why ProductSupport#34
/// shipped: the console's send side throws on every attempt, and nothing here noticed.
/// </summary>
/// <remarks>
/// <para>
/// Asserted through the console's logs rather than by driving an operator command, because operator
/// commands travel CritterWatch's SignalR hub and this harness has no SignalR client. It still pins
/// the defect: the console pushes to a registered service on its own, so a broken send surfaces as
/// <c>BufferedSendingAgent</c> failures in the console log with no operator action at all — exactly
/// how the reporter found it.
/// </para>
/// <para>
/// SKIPPED until this sample bumps past wolverine#3681 (GH-3690). It fails on the pinned WolverineFx
/// 6.23.1 — legitimately, because the control channel really is broken there. Un-skip with the bump;
/// see the warning in README.md.
/// </para>
/// </remarks>
[Fact(Skip = "Control channel is broken on WolverineFx 6.23.1 — un-skip when this sample bumps past wolverine#3681 (GH-3690).")]
public async Task console_control_channel_sends_without_transport_errors()
{
using var client = _fixture.CreateCritterWatchClient();

// Registration first: the console has nothing to send to until OrderService reports its control URI.
await _fixture.WaitForServicesAsync(client, ["OrderService"], timeout: TimeSpan.FromMinutes(2));

// Give the console a window to actually push to the freshly-registered service.
await Task.Delay(TimeSpan.FromSeconds(20));

var consoleLogs = _fixture.DumpResourceLogs(CritterWatchAppHostFixture<Projects.AppHost>.CritterWatchResourceName);

// The GH-3690 signature. Matched on the exception text rather than the sender type so the assertion
// survives Wolverine renaming BufferedSendingAgent.
consoleLogs.ShouldNotContain("An invalid request URI was provided");
consoleLogs.ShouldNotContain("Failed to send outgoing envelopes batch");
}
}