Commit eea3c60
committed
Fix pdb / breakpoint() hang in workflow code (temporalio#1104)
Closes temporalio#1104.
breakpoint() and pdb.set_trace() inside workflow code silently hang
even with debug_mode=True and an unsandboxed runner. Three orthogonal
issues contribute; this PR addresses all three behind the existing
debug_mode flag so production behavior is unchanged.
1. Thread placement. Activations run on a ThreadPoolExecutor worker
thread, so pdb's cmdloop() calls input() from a thread that doesn't
own the controlling TTY. Fixed by scheduling the activation as a
loop.call_soon callback and awaiting a future the callback
completes. The dispatch task suspends at the await so it's no
longer mid-__step() when the workflow's internal task stepping
happens. (A direct synchronous call ran afoul of Python 3.14's
tightened asyncio task-entry validation: "Cannot enter into task
while another task is being executed.")
2. Sandbox restriction. The sandbox flags `breakpoint` and `input` as
non-deterministic builtins. With debug_mode=True the user has
explicitly accepted non-determinism for the debugging session, so
we relax those two specific restrictions when the runner is a
SandboxedWorkflowRunner. Other sandbox checks remain intact.
3. Silent-hang failure mode. Installs a process-wide
sys.breakpointhook at worker startup that raises a clear
RuntimeError when breakpoint() is called from a workflow worker
thread without debug_mode, replacing the silent hang.
Adds a "Debugging Workflows with breakpoint() / pdb" subsection to the
README under Workflow Sandbox, including a runnable example and the
caveats around workflow task timeouts.
Tests at tests/worker/test_breakpoint_hang.py cover thread placement
in both modes, the sandboxed-workflow path, and the defensive hook.
Verified on Python 3.13 and 3.14 locally; CI matrix green on fork.
The load-bearing observation for the dispatch fix: `await future`
suspends the dispatch task such that asyncio no longer considers it
"currently executing," even though it's still in a pending state.
That's what lets workflow.activate(act) step the workflow's internal
task without 3.14's task-entry error.1 parent 7ea54e6 commit eea3c60
3 files changed
Lines changed: 523 additions & 45 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
85 | 86 | | |
86 | 87 | | |
87 | 88 | | |
| |||
1241 | 1242 | | |
1242 | 1243 | | |
1243 | 1244 | | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
| 1278 | + | |
| 1279 | + | |
| 1280 | + | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
| 1285 | + | |
| 1286 | + | |
| 1287 | + | |
| 1288 | + | |
| 1289 | + | |
| 1290 | + | |
| 1291 | + | |
| 1292 | + | |
| 1293 | + | |
| 1294 | + | |
| 1295 | + | |
| 1296 | + | |
| 1297 | + | |
| 1298 | + | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
1244 | 1318 | | |
1245 | 1319 | | |
1246 | 1320 | | |
| |||
0 commit comments