Skip to content

Archive

Debugging

5 articles
Python 09 Sep 2026 12 min read

Debug Running Asyncio Services with pstree and ps in Python 3.14

An asynchronous service can be alive while making no useful progress. The process still responds to signals. CPU usage may be low. The event loop is still running. Yet a request, worker, or shutdown path appears stuck somewhere inside a chain of coroutines. Traditional stack traces are only part of the answer. An asyncio application is organized around tasks and await relationships, so the useful question is often not merely “where is this thread?” but “which task is waiting for which other task?”

Python 09 Sep 2026 12 min read

Attach to Running Python Processes with sys.remote_exec in Python 3.14

A production Python process can be healthy enough to stay alive while still being difficult to understand. Perhaps one thread appears stuck. Memory is growing but the application has no diagnostic endpoint. A profiler was not enabled before startup. Restarting the process would erase the state you need to inspect. Python 3.14 adds a new CPython capability for this situation: sys.remote_exec(). It lets one Python process request that a .py file be executed by another running CPython process. The target executes that file on its main thread at a safe execution point.

Python 09 Sep 2026 11 min read

Attach pdb to Running Python Processes in Python 3.14

A Python service can misbehave without crashing. A worker may loop unexpectedly, a request may remain in an odd state, or a long-running process may hold data that is difficult to reproduce in a development environment. Historically, using pdb in that situation usually required planning ahead. You could add breakpoint() to the code, start the program under the debugger, or restart it with extra instrumentation. Those approaches are useful, but they do not help much when the interesting state already exists inside a running process.

Software Engineering 08 Sep 2026 9 min read

Finding Regressions with Binary Search

A regression appears in the current build, but the same behavior worked two weeks ago. Since then, the team has merged 80 changes. Reading all 80 diffs is possible, but it is slow and gives every change equal attention even though only one boundary in history matters: the point where the behavior changed from working to broken. When revisions are ordered and you can classify a revision reliably as good or bad, you can search that history with the same idea as binary search. Test a revision near the middle. Its result tells you which half can still contain the first bad revision. Repeat until only the transition remains.

Software Engineering 04 Sep 2026 9 min read

Assertions That Expose Broken Assumptions

A program can produce the wrong result long after the code that caused the problem has run. A function corrupts an internal value, several operations accept it, and an unrelated component eventually fails. By then, the stack trace points at the consequence rather than the cause. Assertions help shorten that distance. An assertion states an internal condition that the programmer believes must be true at a particular point in the program. If the condition is false, the program reports a broken assumption immediately instead of continuing as though the state were valid.