Time has the nasty habit of biting you in production when you least expect it. A timestamp that is perfectly suitable for recording when an order was received is a poor way to measure how long a reque
dotnetdigest.com19 min read
The UTC-timestamps-don't-establish-order section is the most quietly dangerous mistake this piece corrects. "Sort by OccurredAtUtc" reads as obviously safe, right up until two events on different machines land within a few milliseconds of each other and the sort silently picks the wrong causal order, no exception, no warning, just a subtly wrong answer that only surfaces when something downstream depends on that order being right. Reaching for a fencing token or version number instead of a timestamp the moment ordering actually matters for correctness is the right instinct, and it's the kind of bug that passes code review easily because a timestamp looks like it should be sufficient.
The clock-ownership principle for expiry and leases is the sharpest architectural point in here. Letting every worker independently compare a stored ExpiresAtUtc against its own local clock turns clock skew into part of your locking protocol without anyone deciding that on purpose, moving the comparison into the same atomic operation as the write (the SQL example) removes an entire class of race condition by construction rather than by discipline. That's a much stronger guarantee than "make sure your NTP sync is good."
"Now should be captured once for one decision" is a small section but probably the easiest bug on this list to actually have shipped, calling GetUtcNow() twice inside one conditional and treating both calls as the same instant is exactly the kind of thing that looks correct in review because the window is usually too small to notice, until it isn't.
This is a really useful breakdown of a topic that is easy to underestimate in .NET systems. The distinction between wall-clock time, elapsed time, business dates, and local schedules is especially important in distributed applications. I also like the emphasis on TimeProvider and moving time forward in tests instead of relying on real delays—it makes both the architecture and the tests much easier to reason about.
Puneet Khandelwal
TThe real bottleneck is rarely the tech, it's usually the people