Anti-Pattern: Blocking I/O in Request Thread
🔴 The Problem
Performing long-running I/O operations (like sending emails via SMTP or making HTTP requests) synchronously within a web request thread.
Signals
- High "Request Queued" metric in generic monitoring (IIS/Azure).
- Users see a loading spinner for 5+ seconds on simple actions (e.g., "Send Confirmation").
- Widespread use of
Thread.Sleepor synchronousSend()methods.
Why it's Bad
- Thread Starvation: In a web server (IIS/ASP.NET), the thread pool is limited. If all threads are busy waiting for SMTP or HTTP responses (which consume 0 CPU but block the thread), the server cannot accept any new requests, even dynamic ones.
- Poor UX: The user is forced to wait for backend machinery that is irrelevant to their immediate action.
💡 The Solution
- Async/Await: Use
await smtpClient.SendMailAsync(...)to release the thread back to the pool while waiting. - Background Jobs: Offload the work entirely to a queue (e.g., Hangfire) and return "Accepted" to the user immediately.
🔍 WEP NG Context & Detection
- Found in
WepEmailGenerator,HomeController, andFollowUpComponentService. WepAutmatedMailer.SendFromParamsis blocking.
# Find usage of Thread.Sleep (A signal of blocking for I/O)
grep -r "Thread.Sleep" . --include="*.cs"
⚖️ Defense
In some cases, blocking I/O is tolerated for simplicity or UX linearity. See: Defender's Advocate #16: Blocking I/O in Request Thread.