Zombie Queries: Your database doesn't know the user left.

A Slow Query

A user opens a page on your app. It needs to pull a large report from the database. Nothing unusual, just a bit slow today.

The user closes the app without waiting for the response from the server.

So what exactly happens with the response?

Nobody Told the Database

Once the request from the client reached the server, the server started executing the business logic in order to fulfill that request. That logic might reach out to a database, or another service, to get what it needs.

But say the client disconnects. The query the request fired is still executing. There's a name for this: a zombie query.

The server might sense the client is gone, but that information never reaches the database. The query just keeps running, unaware.

Why This Is a Problem

Each request-response cycle consumes a certain amount of resources.

If the number of requests is small, this might not even look like an issue or bother your application. But at the scale real-world applications operate at, huge numbers of requests hit the server every second.

There's a limited number of connections we can open with the database, and if they're consumed by zombie queries, other users would suffer. Our application would become slow.

How Do You Fix This?

There needs to be a way to tell the database, or whatever service is involved, to stop as soon as the client disconnects.

So how does the server actually pass that signal along?

One idea: keep a global variable that tracks whether the client is still connected. The moment it changes, stop the request. Sounds fine at first, but it only works if the server is handling one request at a time, and that's almost never true. If multiple clients are hitting the server at once and one of them disconnects, every request would stop, since they're all watching the same shared variable.

So each request needs to be handled on its own. Every request needs its own signal, separate from everyone else's.

And that signal can't just be something we check once in a while, either. The database call might be sitting there, waiting, doing nothing but waiting for a response. So whatever we use has to be something that call can watch while it's waiting, and react the moment it changes.

What This Is Called

Turns out, this isn't something you need to invent yourself. Most programming languages already have a way to do exactly this: signal a request to cancel, and let anything watching that signal react to it, wherever it happens to be running.

In JavaScript, this is done through AbortController.

// JS (e.g. node-postgres)
pool.query(sql, { signal: controller.signal })

In Go, the same idea exists as context.Context, passed as the first argument through every function that needs it.

// Go
db.QueryContext(ctx, query) // cancels the DB query if ctx is cancelled

Different names, same idea: a signal tied to one specific request, passed down through everything that request touches, so that when it's time to stop, everything watching it knows, even the part that's just sitting there, waiting on the database.

So, whatever stack you're using, next time you write a slow database call, pass the request's context or signal into it. That one line is the difference between a query that dies when the user leaves, and a zombie query that finishes work nobody's waiting for anymore.

Closing Thoughts

I hope by now the term Zombie Query makes a lot more sense than it did at the start, and context.Context or AbortController don't feel like magic keywords you're just told to add.

This is what I meant earlier too. It's easy to copy db.QueryContext(ctx, ...) from a Stack Overflow answer or have AI generate it for you. But if you don't know why that ctx needs to be there, you won't recognize it the next time it shows up somewhere else, in some other shape, in some other language. Understanding the actual problem is what makes the solution stick.

So, at the end I would like to thank you for taking out your valuable time for reading this and hope you always stay happy, healthy and blessed.

This is Mukul Padwal signing off.

If you have any doubt, suggestions about what could be improved you can always reach me out via my socials. Links below

MP

@mukulpadwal

Portfolio assistant

Ask me about this page