Commit fe3aab6
Run license validation off the construction path (fixes #4640)
MapperConfiguration validated the license key synchronously in its
constructor via Task.Run(() => handler.ValidateTokenAsync(...)).GetResult().
Under a lazily-built DI singleton (e.g. Lamar) that runs while the container
holds its singleton-build lock, and Task.Run needs a free thread-pool thread
to complete. During a cold start that takes immediate traffic the pool is
saturated (every request thread is parked waiting on that same lock), so the
queued validation work can never be scheduled — the lock holder blocks
forever and the whole app convoys behind it. A production dump on 16.1.1 in
#4640 shows exactly this: one lock owner, 524 waiters, CPU idle.
The validated license is logging-only: LicenseValidator.Validate just emits
log messages and gates no mapping behavior, and the result has exactly one
reader (this call). So validation need not be synchronous and can move off
the construction path entirely:
- MapperConfiguration: offload validation+logging to a dedicated LongRunning
thread (Task.Factory.StartNew + TaskScheduler.Default) and return
immediately. The constructor never blocks under the DI lock, so it can't
deadlock regardless of pool state. The body is wrapped in try/catch so a
faulted fire-and-forget task can't surface as an unobserved exception.
- LicenseAccessor.ValidateKey: drop the Task.Run wrapper now that validation
always runs on that dedicated background thread (no SynchronizationContext,
and local JWT validation completes synchronously, so no pool dependency).
Adds a regression test asserting validation logs on a different thread than
the constructor's (fails on the old synchronous behavior, passes here).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent fed6e64 commit fe3aab6
3 files changed
Lines changed: 90 additions & 3 deletions
File tree
- src
- AutoMapper
- Configuration
- Licensing
- UnitTests/Licensing
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
119 | | - | |
120 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
121 | 129 | | |
122 | 130 | | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
123 | 147 | | |
124 | 148 | | |
125 | 149 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
88 | 91 | | |
89 | 92 | | |
90 | 93 | | |
| |||
Lines changed: 60 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 | + | |
0 commit comments