For a long time I treated context.Context as a nuisance. It's that ctx parameter cluttering every function signature, the thing the linter nags you about, and I'd cheat by stashing one in a struct field or passing context.Background() deep down because I couldn't be bothered to thread the real one through. Then I had a request that wouldn't die.
A client disconnected, but our handler kept going: still querying the database, still calling upstream, still burning resources for an answer nobody would ever read. The reason was simple. I'd broken the chain. Somewhere in the middle, a function had quietly substituted a fresh Background context, and from that point down nothing knew the caller had left. Cancellation only works if the context actually flows from the top to the bottom, unbroken.
So I stopped fighting it. Context goes first, every function, no exceptions, and you pass the one you were given, not a new one. It's not decoration. It's a live wire carrying "should I still be doing this" all the way down, and the deadline and the cancel signal only reach the database driver if you've handed it through every layer in between. The clutter is the feature. Once I accepted that, the convention stopped feeling like ceremony and started feeling like plumbing that just needs connecting properly.