Commit 81925d8
fix: suppress APM error events for receive-loop cancellations during shutdown (5.7.5) (#116)
* fix: suppress APM error events for receive-loop cancellations during shutdown (5.7.5)
Setting Outcome=Success (5.7.4) was insufficient: Elastic APM captures error
events at the DiagnosticSource level before ReceiverWrapper runs, so the error
document was already queued regardless of the outcome override.
Registers a one-time Agent.AddFilter(IError) that drops error events whose
TransactionId matches a cancelled-receive transaction, preventing them from
reaching the APM server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: suppress auto-instrumented AmqpReceiver TaskCanceledException APM errors during shutdown (5.7.5)
Root cause: Elastic APM creates "AzureServiceBus RECEIVE" transactions via DiagnosticSource
auto-instrumentation. The Azure SDK ends its Activity before firing ProcessErrorAsync, so
Agent.Tracer.CurrentTransaction is null in OnReceiveCancelled() — the TX ID is never tracked
and the filter passes the error through. Fix: add culprit-based suppression for
TaskCanceledException on the AmqpReceiver path (post-WebSockets fix, only fires on shutdown).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address review feedback — TryRemove, AmqpReceiverCulprit const, cap comment, filter tests
- Replace ContainsKey with TryRemove in the filter so matched transaction IDs are consumed
on first use, keeping the dictionary lean and avoiding unnecessary cap pressure
- Extract 'AmqpReceiver' magic string to private const AmqpReceiverCulprit with comment
documenting the Azure SDK source and why the culprit path is safe post-WebSockets fix
- Extract ShouldSuppressError as an internal static method for unit testability
- Add inline comment at the CancelledTransactionIdCap guard explaining the culprit fallback
- Add InternalsVisibleTo("Ev.ServiceBus.UnitTests") to Ev.ServiceBus.Apm
- Add ApmTransactionManagerTests: 8 tests covering both filter paths, the TryRemove
consume-once behaviour, and non-suppressed exception types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address Michal's follow-up — add parens, TOCTOU comment, cap-exceeded test
- Add explicit parentheses around the is-pattern in ShouldSuppressError to document
operator precedence intent: (exceptionType is "TCE" or "OCE") && culprit.Contains(...)
- Document the non-atomic Count+TryAdd in OnReceiveCancelled as an intentional soft cap
- Add ShouldSuppressError_WhenCapExceeded_CulpritPathStillSuppresses test: seeds 1000
entries to simulate cap exhaustion, then verifies the culprit path still suppresses
the error for an untracked transaction ID
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: ensure APM error filter is registered before first message processing (5.7.5)
The Service Bus hosted service starts before the Elastic APM hosted service
(DI registration order in consuming apps), so Agent.IsConfigured is false
when ApmTransactionManager is constructed and the constructor's filter
registration is silently skipped.
RegisterShutdownErrorFilter() is now also called:
- At the start of RunWithInTransaction() when IsTraceEnabled() is true
(agent is definitively up; O(1) no-op on all subsequent calls via
Interlocked.CompareExchange guard)
- Before the IsTraceEnabled() guard in OnReceiveCancelled()
This guarantees the filter is in place before the first message processing
completes and before any graceful-shutdown RECEIVE activity errors can fire.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: clarify Case 1 type-safety and cap behaviour in ApmTransactionManager
Address review comments from PR #116:
- Case 1 has no exceptionType guard because _cancelledTransactionIds is
populated exclusively via OnReceiveCancelled(), which ReceiverWrapper
only calls for OperationCanceledException.
- Cap overflow for non-AmqpReceiver paths won't be suppressed; this is
documented as acceptable given the conditions required to reach it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Robert Karp <rkarp@ecovadisazure.onmicrosoft.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent f0e645f commit 81925d8
5 files changed
Lines changed: 244 additions & 3 deletions
File tree
- docs
- src/Ev.ServiceBus.Apm
- tests/Ev.ServiceBus.UnitTests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
7 | 13 | | |
8 | 14 | | |
9 | 15 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
| 5 | + | |
4 | 6 | | |
5 | 7 | | |
6 | 8 | | |
| |||
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
17 | 56 | | |
18 | 57 | | |
19 | 58 | | |
20 | 59 | | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
21 | 65 | | |
22 | 66 | | |
23 | 67 | | |
| |||
73 | 117 | | |
74 | 118 | | |
75 | 119 | | |
76 | | - | |
77 | | - | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
78 | 138 | | |
79 | 139 | | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
80 | 185 | | |
81 | 186 | | |
82 | | - | |
| 187 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
21 | 25 | | |
Lines changed: 125 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
0 commit comments