Skip to content

Commit 3a0cdb8

Browse files
chujchenmatthewrobertson
authored andcommitted
feat: avoid long running process when request timeout (#309)
Previously function framework use 0 timeout which is actually "no timeout" restrction. This was causing a problem that when user provides a request timeout to Cloud function, process will still continue and consume resources. In this fix, timeout is enabled; default timeout settings is 5 min, same as Cloud run. To make sure timeout settings will be respected, default settings switched from multi-threads to multi-workers. However, user is still allowed to customize workers/threads by assigning env var. But user need to note that timeout won't work when #thread > 1.
1 parent e175553 commit 3a0cdb8

File tree

4 files changed

+19
-18
lines changed

4 files changed

+19
-18
lines changed

src/functions_framework/__init__.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ def write(self, out):
6565

6666
def cloud_event(func: CloudEventFunction) -> CloudEventFunction:
6767
"""Decorator that registers cloudevent as user function signature type."""
68-
_function_registry.REGISTRY_MAP[
69-
func.__name__
70-
] = _function_registry.CLOUDEVENT_SIGNATURE_TYPE
68+
_function_registry.REGISTRY_MAP[func.__name__] = (
69+
_function_registry.CLOUDEVENT_SIGNATURE_TYPE
70+
)
7171

7272
@functools.wraps(func)
7373
def wrapper(*args, **kwargs):
@@ -105,9 +105,9 @@ def wrapper(*args, **kwargs):
105105

106106
def http(func: HTTPFunction) -> HTTPFunction:
107107
"""Decorator that registers http as user function signature type."""
108-
_function_registry.REGISTRY_MAP[
109-
func.__name__
110-
] = _function_registry.HTTP_SIGNATURE_TYPE
108+
_function_registry.REGISTRY_MAP[func.__name__] = (
109+
_function_registry.HTTP_SIGNATURE_TYPE
110+
)
111111

112112
@functools.wraps(func)
113113
def wrapper(*args, **kwargs):

src/functions_framework/_http/gunicorn.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ class GunicornApplication(gunicorn.app.base.BaseApplication):
2121
def __init__(self, app, host, port, debug, **options):
2222
self.options = {
2323
"bind": "%s:%s" % (host, port),
24-
"workers": 1,
25-
"threads": (os.cpu_count() or 1) * 4,
26-
"timeout": 0,
24+
"workers": os.environ.get("WORKERS", (os.cpu_count() or 1) * 4),
25+
"threads": os.environ.get("THREADS", 1),
26+
"timeout": os.environ.get("CLOUD_RUN_TIMEOUT_SECONDS", 300),
2727
"loglevel": "error",
2828
"limit_request_line": 0,
2929
}
3030
self.options.update(options)
3131
self.app = app
32+
3233
super().__init__()
3334

3435
def load_config(self):

src/functions_framework/_typed_event.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ def register_typed_event(decorator_type, func):
4848
)
4949

5050
_function_registry.INPUT_TYPE_MAP[func.__name__] = input_type
51-
_function_registry.REGISTRY_MAP[
52-
func.__name__
53-
] = _function_registry.TYPED_SIGNATURE_TYPE
51+
_function_registry.REGISTRY_MAP[func.__name__] = (
52+
_function_registry.TYPED_SIGNATURE_TYPE
53+
)
5454

5555

5656
""" Checks whether the response type of the typed function has a to_dict method"""

tests/test_http.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,17 @@ def test_gunicorn_application(debug):
9797
assert gunicorn_app.app == app
9898
assert gunicorn_app.options == {
9999
"bind": "%s:%s" % (host, port),
100-
"workers": 1,
101-
"threads": os.cpu_count() * 4,
102-
"timeout": 0,
100+
"workers": os.cpu_count() * 4,
101+
"threads": 1,
102+
"timeout": 300,
103103
"loglevel": "error",
104104
"limit_request_line": 0,
105105
}
106106

107107
assert gunicorn_app.cfg.bind == ["1.2.3.4:1234"]
108-
assert gunicorn_app.cfg.workers == 1
109-
assert gunicorn_app.cfg.threads == os.cpu_count() * 4
110-
assert gunicorn_app.cfg.timeout == 0
108+
assert gunicorn_app.cfg.workers == os.cpu_count() * 4
109+
assert gunicorn_app.cfg.threads == 1
110+
assert gunicorn_app.cfg.timeout == 300
111111
assert gunicorn_app.load() == app
112112

113113

0 commit comments

Comments
 (0)