You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 86f06ef
Browse filesBrowse the repository at this point in the historyBrowse files
fix(serverless): keep log capture and shutdown behavior off the existing path
An audit of the most popular worker templates showed this feature reaching
workers that never asked for it. Two of them install the SDK unpinned, so they
take whatever we publish, and both fill the buffer with operational chatter while
returning errors rather than raising, so the capture was pure exposure with no
benefit. Meanwhile the workers the feature was built for run their engine as a
subprocess, whose output arrives on inherited file descriptors and was never
capturable in the first place.
Make capture opt-in. RUNPOD_LOG_CAPTURE=auto, the default, installs the proxy
only when prestart hooks are registered, so a worker that has not adopted
prestart is untouched: streams unwrapped, payload unchanged. `all` and `off`
force it either way.
Stop truncating what this feature did not add. A handler's error_message and
error_traceback are reported in full again; 16KB is well under the size of a
real framework traceback, and the job-done body limit was not this change's
problem to solve. Only the logs field stays bounded.
Restore the in-flight job-take on ordinary shutdown. The platform assigns a job
before writing the take response and does not release it when the client
disconnects, so aborting a take that already carries one strands that request
until the heartbeat sweeper reclaims it, spending its single retry. Prestart
failure already had a grace period for this; every other shutdown now gets a
short one.
Also make the proxy indistinguishable from the stream it wraps: register it on
io.TextIOBase so isinstance checks still pass (subclassing would shadow
encoding with None), and capture writelines, which bypassed write().
Document what capture cannot see: child processes, log handlers constructed
before startup, and plain threads.
Copy file name to clipboardExpand all lines: docs/serverless/worker.md
+31-15Lines changed: 31 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -94,9 +94,9 @@ when hooks are registered. It never silently skips registered startup work.
94
94
95
95
## Failure logs
96
96
97
-
When a handler or a prestart hook fails, the SDK attaches the last 16 KB of
98
-
whatever the worker wrote to `stdout`/`stderr` to the failure it returns, under
99
-
a `logs` key:
97
+
When a prestart hook or a handler fails, the SDK can attach the last 16 KB of
98
+
whatever the worker wrote to `stdout`/`stderr` to the failure it reports, under a
99
+
`logs` key:
100
100
101
101
```json
102
102
{
@@ -107,20 +107,36 @@ a `logs` key:
107
107
}
108
108
```
109
109
110
-
That payload is returned to whoever called the request, so anything the worker
111
-
prints can reach the caller. On a private endpoint the caller is you, and the
112
-
same output is already in your worker logs. On a public or shared endpoint the
113
-
caller is a third party. If your worker prints credentials, connection strings,
114
-
or other data you do not want returned, either stop printing them or turn
115
-
capture off:
110
+
That payload is returned to whoever called the request, so capture is **not on by
111
+
default**. `RUNPOD_LOG_CAPTURE` controls it:
116
112
117
-
```bash
118
-
RUNPOD_SKIP_LOG_CAPTURE=true
119
-
```
113
+
| Value | Behavior |
114
+
|-------|----------|
115
+
|`auto` (default) | Capture only when prestart hooks are registered. A worker that has not adopted prestart hooks is untouched: streams are not wrapped and no `logs` key is added. |
116
+
|`all`| Always capture, including handler failures on workers with no prestart hooks. |
117
+
|`off`| Never capture, even with prestart hooks registered. |
118
+
119
+
Only the `logs` field is bounded. `error_message` and `error_traceback` are
120
+
reported in full, exactly as they were before this feature existed.
121
+
122
+
### What capture can and cannot see
123
+
124
+
Capture replaces `sys.stdout`/`sys.stderr` at worker startup, so it sees `print`
125
+
and direct stream writes made while a hook or handler runs. It does **not** see:
126
+
127
+
-**Child processes.** A subprocess inherits file descriptors 1 and 2 directly,
128
+
below Python. If your worker runs an engine as a subprocess and wants its output
129
+
captured, pipe it (`subprocess.Popen(..., stdout=PIPE)`) and re-emit the lines.
130
+
-**Log handlers created before startup.**`logging.StreamHandler` resolves
131
+
`sys.stderr` once, when it is constructed. A `logging.basicConfig()` at module
132
+
import binds the real stream before the SDK starts, so those records bypass
133
+
capture. Call `logging.basicConfig()` from inside a prestart hook if you want
134
+
its output attached.
135
+
-**Plain threads.** Output from a thread your code starts directly is not
136
+
captured; `asyncio.to_thread` is.
120
137
121
-
With capture off, failures still report the exception type, message, and
122
-
traceback; only the `logs` key is dropped. Output always continues to reach your
123
-
worker logs either way.
138
+
In all of these cases output still reaches your worker logs as usual — only the
0 commit comments