cloudflare
workerd
BlogDocsChangelog

Handle CPU limit exceeded in Python workers

#5543Merged
Comparing
hoodmane/python-cpu-limiter
(
49ec0b1
) with
main
(
1a26e6a
)
CodSpeed Performance Gauge
0%
Untouched
57
Skipped
30

Benchmarks

Skipped (30)

Passed

arrayBufferBody[Response]
src/workerd/tests/bench-response.c++
CodSpeed Performance Gauge
+2%
16.8 µs16.5 µs
nullBodyWithStatus[Response]
src/workerd/tests/bench-response.c++
CodSpeed Performance Gauge
+1%
9.6 µs9.5 µs
simpleStringBody[Response]
src/workerd/tests/bench-response.c++
CodSpeed Performance Gauge
+1%
21.4 µs21.2 µs
bodyWithHeaders[Response]
src/workerd/tests/bench-response.c++
CodSpeed Performance Gauge
+1%
23.5 µs23.4 µs
EncodeInto_OneByte_256[TextEncoder][1/1/256]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
4.5 ms4.5 ms
EncodeInto_TwoByte_256[TextEncoder][1/2/256]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
5.4 ms5.4 ms
request[RegExpBenchmark]
src/workerd/tests/bench-regex.c++
CodSpeed Performance Gauge
0%
7.3 ms7.3 ms
EncodeInto_OneByte_1024[TextEncoder][1/1/1024]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
10.5 ms10.5 ms
set_append[ApiHeaders]
src/workerd/tests/bench-api-headers.c++
CodSpeed Performance Gauge
0%
16.9 ms16.9 ms
request[GlobalScopeBenchmark]
src/workerd/tests/bench-global-scope.c++
CodSpeed Performance Gauge
0%
53 ms52.9 ms
EncodeInto_TwoByte_1024[TextEncoder][1/2/1024]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
14.1 ms14.1 ms
EncodeInto_OneByte_8192[TextEncoder][1/1/8192]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
66.9 ms66.9 ms
constructor[ApiHeaders]
src/workerd/tests/bench-api-headers.c++
CodSpeed Performance Gauge
0%
97.3 ms97.3 ms
Test_JSON_ENC
src/workerd/tests/bench-json.c++
CodSpeed Performance Gauge
0%
205.5 ms205.5 ms
Serialize
src/workerd/tests/bench-mimetype.c++::Mimetype
CodSpeed Performance Gauge
0%
74.6 ms74.6 ms
bm_Immediate
external/capnp-cpp/src/kj/async-bench.c++
CodSpeed Performance Gauge
0%
3.5 µs3.5 µs
bm_ReadyNow
external/capnp-cpp/src/kj/async-bench.c++
CodSpeed Performance Gauge
0%
2.1 µs2.1 µs
bm_coroCoAwaitImmediate
external/capnp-cpp/src/kj/async-bench.c++
CodSpeed Performance Gauge
0%
6.1 µs6.1 µs
bm_coroCoReturn
external/capnp-cpp/src/kj/async-bench.c++
CodSpeed Performance Gauge
0%
4.5 µs4.5 µs
JsString_Utf8Length_Latin1_Flat_256
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
1.7 µs1.7 µs
JsString_Utf8Length_Utf16_Flat_256
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
2.7 µs2.7 µs
JsString_Utf8Length_Latin1_Flat_8192
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
31 µs31 µs
JsString_Utf8Length_Latin1_Flat_1024
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
4.6 µs4.6 µs
JsString_Utf8Length_Latin1_NonFlat_1024
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
12.3 µs12.3 µs
JsString_Utf8Length_Latin1_NonFlat_8192
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
42.1 µs42.1 µs
JsString_Utf8Length_Latin1_Flat_32
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
891.1 ns891.1 ns
JsString_Utf8Length_Utf16_Invalid_Flat_1024
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
8.5 µs8.5 µs
JsString_Utf8Length_Utf16_Flat_1024
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
8.5 µs8.5 µs
JsString_Utf8Length_Utf16_Invalid_NonFlat_256
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
9 µs9 µs
JsString_Utf8Length_Utf16_Flat_8192
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
62.8 µs62.8 µs
JsString_Utf8Length_Utf16_Invalid_Flat_8192
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
62.8 µs62.8 µs
JsString_Utf8Length_Latin1_NonFlat_256
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
8 µs8 µs
JsString_Utf8Length_Utf16_Invalid_NonFlat_1024
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
16.3 µs16.3 µs
JsString_Utf8Length_Utf16_NonFlat_256
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
9 µs9 µs
JsString_Utf8Length_Utf16_Invalid_NonFlat_8192
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
73.9 µs73.9 µs
JsString_Utf8Length_Utf16_NonFlat_1024
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
16.2 µs16.2 µs
JsString_Utf8Length_Utf16_Invalid_Flat_256
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
2.7 µs2.7 µs
JsString_Utf8Length_Utf16_NonFlat_8192
src/workerd/tests/bench-jsstring.c++
CodSpeed Performance Gauge
0%
73.9 µs73.9 µs
Parse[KjHeaders]
src/workerd/tests/bench-kj-headers.c++
CodSpeed Performance Gauge
0%
44.5 µs44.5 µs
EncodeInto_TwoByte_8192[TextEncoder][1/2/8192]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
96.7 ms96.7 ms
Util_RecursivelyFreeze
src/workerd/tests/bench-util.c++
CodSpeed Performance Gauge
0%
10.8 ms10.8 ms
Test_JSON_DEC
src/workerd/tests/bench-json.c++
CodSpeed Performance Gauge
0%
3.2 s3.2 s
ParseAndSerialize
src/workerd/tests/bench-mimetype.c++::Mimetype
CodSpeed Performance Gauge
0%
74.9 ms74.9 ms
Encode_TwoByte_8192[TextEncoder][0/2/8192]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
146.2 ms146.2 ms
jsonResponse[Response]
src/workerd/tests/bench-response.c++
CodSpeed Performance Gauge
0%
35.1 µs35.1 µs
Encode_OneByte_8192[TextEncoder][0/1/8192]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
85.1 ms85.2 ms
Encode_ASCII_8192[TextEncoder][0/0/8192]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
13.1 ms13.1 ms
Encode_TwoByte_1024[TextEncoder][0/2/1024]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
19.5 ms19.6 ms
EncodeInto_ASCII_256[TextEncoder][1/0/256]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
2.5 ms2.6 ms
Encode_OneByte_1024[TextEncoder][0/1/1024]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
12.1 ms12.1 ms
Encode_TwoByte_256[TextEncoder][0/2/256]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
0%
7.1 ms7.1 ms
Encode_OneByte_256[TextEncoder][0/1/256]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
-1%
5.3 ms5.3 ms
EncodeInto_ASCII_8192[TextEncoder][1/0/8192]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
-1%
3.3 ms3.3 ms
EncodeInto_ASCII_1024[TextEncoder][1/0/1024]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
-1%
2.6 ms2.6 ms
Encode_ASCII_32[TextEncoder][0/0/32]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
-1%
3 ms3.1 ms
Encode_ASCII_1024[TextEncoder][0/0/1024]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
-1%
3.7 ms3.8 ms
Encode_ASCII_256[TextEncoder][0/0/256]
src/workerd/tests/bench-text-encoder.c++
CodSpeed Performance Gauge
-1%
3.2 ms3.2 ms

Commits

Click on a commit to change the comparison range
Base
main
1a26e6a
-0.01%
Handle CPU limit exceeded in Python workers If we call `TerminateExecution()`, it will exit Python execution without unwinding the stack or cleaning up the runtime state. This leaves the Python runtime in a permanently messed up state and all further requests will fail. This adds a new `cpuLimitNearlyExceededCallback` to the limit enforcer and hooks it up so that it triggers a SIGINT inside of Python. This can be used to raise a `CpuLimitExceeded` Python error into the runtime. If this error is ignored, then we'll hit the hard limit and be terminated. If we ever do call `TerminateExecution()` on a Python isolate, we should condemn the isolate, but that is left as a TODO. To trigger the SIGINT inside of Python, we have to set two addresses: 1. we set `emscripten_signal_clock` to `0` to make the Python eval breaker check for a signal on the next tick. 2. we set `_Py_EMSCRIPTEN_SIGNAL_HANDLING` to 1 to make Python check the signal clock. We also have to set `Module.Py_EmscriptenSignalBuffer` to a buffer with the number of the signal we wish to trip in it (`SIGINT` aka 2). When we start a request we set `_Py_EMSCRIPTEN_SIGNAL_HANDLING` to 0 to avoid ongoing costs of calling out to JavaScript to check the buffer when no signal is set, and we put a 2 into `Py_EmscriptenSignalBuffer`. The most annoying aspect of this is that the symbol `emscripten_signal_clock` is not exported. For Pyodide 0.28.2, I manually located the address of this symbol and hard coded it. For the next Pyodide, we'll make sure to export it.
49ec0b1
16 days ago
by hoodmane
© 2025 CodSpeed Technology
Home Terms Privacy Docs