fix(common): isolate every event multicast across the codebase#188
Draft
ottobolyos wants to merge 29 commits into
Draft
fix(common): isolate every event multicast across the codebase#188ottobolyos wants to merge 29 commits into
ottobolyos wants to merge 29 commits into
Conversation
09277af to
f7dd36e
Compare
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Jun 3, 2026
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Jun 3, 2026
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Jun 3, 2026
Each HTTP sub-client class -- MTConnectHttpProbeClient, MTConnectHttpCurrentClient, MTConnectHttpSampleClient, MTConnectHttpAssetClient, and MTConnectHttpClientStream -- now iterates the multicast invocation list at every event raise site so one throwing subscriber cannot starve later subscribers. Faults are forwarded through the class's own InternalError event; a faulting InternalError handler is also swallowed so the originating fan-out keeps going. Mirrors the existing per-class helper pattern already applied to the outer MTConnectHttpClient. The sub-classes do not share a base type, so a per-class private RaiseEvent helper keeps each class's InternalError routing self-contained and adds no inheritance pressure. MTConnectHttpClientStream gets both the generic RaiseEvent<T> and a non-generic RaiseEvent sibling for the lifecycle events (Starting, Started, Stopping, Stopped).
…n multicast test files
…m-delegate events
Bare Raise{T} in the class-level summaries of
MqttClientMulticastIsolationTests, HttpServerMulticastIsolationTests,
and ShdrMulticastIsolationTests is ambiguous between the
EventHandler{T} overload (phase 1) and the generic-delegate overload
(phase 2b). docfx metadata with TreatWarningsAsErrors=true promotes
the resulting CS0419 to a build error, breaking the "Prepare generated
docs" CI job.
Replace each bare Raise{T} cref with the fully-qualified parameter
list that matches the overload the test class exercises. Also
disambiguate the Raise(EventHandler, ...) cross-reference in
MulticastIsolation.cs line 48 (non-generic overload summary).
f6bc213 to
4ccfc69
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR #185 introduced per-delegate isolation for the
DeviceReceivedevent so a throwing subscriber no longer cuts off downstream handlers, with swallowed faults routed throughInternalError. This PR closes the same bug class atomically across the entire codebase: the HTTP client surface (outer client and every sub-client), the HTTP server surface, both MQTT clients, the SHDR adapter and client, the device finder, and the agent / broker.Changes
Shared helper
libraries/MTConnect.NET-Common/MulticastIsolation.cs— adds three overloads ofMulticastIsolation.Raise:Raise<T>(EventHandler<T>, object, T, EventHandler<Exception>)— genericEventHandler<T>events.Raise(EventHandler, object, EventArgs, EventHandler<Exception>)— non-genericEventHandlerevents.Raise<TDelegate>(TDelegate, Action<TDelegate>, EventHandler<Exception>, object)— any custom delegate shape; the caller supplies the invocation lambda so no per-signature overload is required.All three overloads share the same contract: a throwing subscriber cannot starve later subscribers; subscriber faults are routed through the caller-supplied
internalErrorsink, which is itself iterated per-delegate so a throwing fault reporter cannot starve later fault reporters; secondary faults from theinternalErrorhandler are terminal and swallowed.HTTP clients
libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpClient.cs,MTConnectHttpProbeClient.cs,MTConnectHttpCurrentClient.cs,MTConnectHttpSampleClient.cs,MTConnectHttpAssetClient.cs,MTConnectHttpClientStream.cs— every?.Invokeraise site replaced with the appropriateMulticastIsolation.Raisecall across the outer client and every sub-client.MQTT clients
libraries/MTConnect.NET-MQTT/Clients/MTConnectMqttClient.cs— 16 raise sites:ClientStarting,ClientStopping,ClientStarted,ClientStopped,ConnectionError,InternalError,DeviceReceived,ProbeReceived,ResponseReceived(×2),CurrentReceived,ObservationReceived(×2),SampleReceived,AssetsReceived,AssetReceived.libraries/MTConnect.NET-MQTT/Clients/MTConnectMqttExpandedClient.cs— 9 raise sites:ClientStarting,ClientStopping,ClientStarted,ClientStopped,ConnectionError,InternalError,ObservationReceived(×2),ConnectionStatusChanged(×2),DeviceReceived,AssetReceived.SHDR adapter and client
libraries/MTConnect.NET-SHDR/Adapters/ShdrAdapter.cs— 8 raise sites:AgentConnected,AgentDisconnected,PingReceived,PongSent,ConnectionError,LineSent(×2),SendError(×2).libraries/MTConnect.NET-SHDR/Shdr/ShdrClient.cs— 20 raise sites:Connected,PingSent(×2),ConnectionError(×2),Disconnected(×2),Listening,PongReceived,ProtocolReceived(×11).Device finder
libraries/MTConnect.NET-DeviceFinder/MTConnectDeviceFinder.cs— 8 raise sites:PingSent,PingReceived,SearchCompleted,PortOpened,PortClosed,ProbeSent,DeviceFound,ProbeSuccessful.libraries/MTConnect.NET-DeviceFinder/PingQueue.cs— 3 raise sites:PingSent,PingReceived,Completed.These classes declare every event with a custom delegate shape (
DeviceHandler,PingSentHandler,RequestStatusHandler, etc.); each site uses the newRaise<TDelegate>(handler, invoke)overload with the per-subscriber invocation passed inline.Agent and broker
libraries/MTConnect.NET-Common/Agents/MTConnectAgent.cs— 15 raise sites total: theEventHandler<T>eventsDeviceAdded,ObservationReceived,ObservationAdded(×4),AssetAdded, plus the custom-delegate validation eventsInvalidComponentAdded,InvalidCompositionAdded,InvalidDataItemAdded,InvalidObservationAdded(×3),InvalidDeviceAdded,InvalidAssetAdded(×2).libraries/MTConnect.NET-Common/Agents/MTConnectAgentBroker.cs— 35 raise sites total: theEventHandlereventStreamsResponseSent(×12), plus the custom-delegate request / response eventsDevicesRequestReceived(×2),DevicesResponseSent(×2),StreamsRequestReceived(×12),AssetsRequestReceived,DeviceAssetsRequestReceived,AssetsResponseSent(×2),ErrorResponseSent(×2).HTTP server
libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpResponseHandler.cs— 5 raise sites:ClientConnected,ResponseSent,ClientDisconnected(×3),ClientException(×2).libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpServerStream.cs— 5 raise sites:StreamStarted,HeartbeatReceived,DocumentReceived,StreamException,StreamStopped.Test coverage
tests/MTConnect.NET-Common-Tests/MulticastIsolationTests.cs— helper unit tests for all three overloads, including the generic-delegate path.tests/MTConnect.NET-Common-Tests/MqttClientMulticastIsolationTests.cs— helper contract tests for the delegate shapes used by both MQTT clients.tests/MTConnect.NET-Common-Tests/DeviceFinderMulticastIsolationTests.cs— helper contract tests for every custom-delegate shape declared onMTConnectDeviceFinderandPingQueue.tests/MTConnect.NET-Common-Tests/Agents/AgentMulticastIsolationTests.cs— helper contract tests for every event onMTConnectAgentandMTConnectAgentBroker, including the validation and request / response custom delegates.tests/MTConnect.NET-SHDR-Tests/ShdrMulticastIsolationTests.cs— helper contract tests forEventHandler<string>,EventHandler<AdapterEventArgs<string>>,EventHandler<AdapterEventArgs<Exception>>, andEventHandler<Exception>shapes.tests/MTConnect.NET-HTTP-Tests/Clients/MulticastIsolationTests.cs,NonGenericMulticastIsolationTests.cs,SubClientMulticastIsolationTests.cs— positive (multi-subscriber fan-out) and negative (InternalError-itself-throws) tests per raise site on the HTTP client surface.tests/MTConnect.NET-HTTP-Tests/Integration/DevicesAndDeviceReceivedIntegrationTests.cs— end-to-end test for the probe →Devicescache →DeviceReceivedflow.tests/MTConnect.NET-HTTP-Tests/Servers/HttpServerMulticastIsolationTests.cs— helper contract tests for the HTTP server delegate shapes.Verification
dotnet build MTConnect.NET.sln— green (0 warnings, 0 errors).dotnet test MTConnect.NET.sln --filter "Category!=E2E&Category!=RequiresDocker&Category!=XsdLoadStrict"— green (4831 / 4831).dotnet test tests/MTConnect.NET-Common-Tests --filter "FullyQualifiedName~MulticastIsolation"— green (80 / 80).