Skip to main content

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.Sleep or synchronous Send() 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

  1. Async/Await: Use await smtpClient.SendMailAsync(...) to release the thread back to the pool while waiting.
  2. 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, and FollowUpComponentService.
  • WepAutmatedMailer.SendFromParams is 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.