Skip to content

Commit

Permalink
feat: avoid long running process when request timeout (#309)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
KAKAinGoog authored and matthewrobertson committed Apr 29, 2024
1 parent e175553 commit 3a0cdb8
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 18 deletions.
12 changes: 6 additions & 6 deletions src/functions_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ def write(self, out):

def cloud_event(func: CloudEventFunction) -> CloudEventFunction:
"""Decorator that registers cloudevent as user function signature type."""
_function_registry.REGISTRY_MAP[
func.__name__
] = _function_registry.CLOUDEVENT_SIGNATURE_TYPE
_function_registry.REGISTRY_MAP[func.__name__] = (
_function_registry.CLOUDEVENT_SIGNATURE_TYPE
)

@functools.wraps(func)
def wrapper(*args, **kwargs):
Expand Down Expand Up @@ -105,9 +105,9 @@ def wrapper(*args, **kwargs):

def http(func: HTTPFunction) -> HTTPFunction:
"""Decorator that registers http as user function signature type."""
_function_registry.REGISTRY_MAP[
func.__name__
] = _function_registry.HTTP_SIGNATURE_TYPE
_function_registry.REGISTRY_MAP[func.__name__] = (
_function_registry.HTTP_SIGNATURE_TYPE
)

@functools.wraps(func)
def wrapper(*args, **kwargs):
Expand Down
7 changes: 4 additions & 3 deletions src/functions_framework/_http/gunicorn.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ class GunicornApplication(gunicorn.app.base.BaseApplication):
def __init__(self, app, host, port, debug, **options):
self.options = {
"bind": "%s:%s" % (host, port),
"workers": 1,
"threads": (os.cpu_count() or 1) * 4,
"timeout": 0,
"workers": os.environ.get("WORKERS", (os.cpu_count() or 1) * 4),
"threads": os.environ.get("THREADS", 1),
"timeout": os.environ.get("CLOUD_RUN_TIMEOUT_SECONDS", 300),
"loglevel": "error",
"limit_request_line": 0,
}
self.options.update(options)
self.app = app

super().__init__()

def load_config(self):
Expand Down
6 changes: 3 additions & 3 deletions src/functions_framework/_typed_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ def register_typed_event(decorator_type, func):
)

_function_registry.INPUT_TYPE_MAP[func.__name__] = input_type
_function_registry.REGISTRY_MAP[
func.__name__
] = _function_registry.TYPED_SIGNATURE_TYPE
_function_registry.REGISTRY_MAP[func.__name__] = (
_function_registry.TYPED_SIGNATURE_TYPE
)


""" Checks whether the response type of the typed function has a to_dict method"""
Expand Down
12 changes: 6 additions & 6 deletions tests/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@ def test_gunicorn_application(debug):
assert gunicorn_app.app == app
assert gunicorn_app.options == {
"bind": "%s:%s" % (host, port),
"workers": 1,
"threads": os.cpu_count() * 4,
"timeout": 0,
"workers": os.cpu_count() * 4,
"threads": 1,
"timeout": 300,
"loglevel": "error",
"limit_request_line": 0,
}

assert gunicorn_app.cfg.bind == ["1.2.3.4:1234"]
assert gunicorn_app.cfg.workers == 1
assert gunicorn_app.cfg.threads == os.cpu_count() * 4
assert gunicorn_app.cfg.timeout == 0
assert gunicorn_app.cfg.workers == os.cpu_count() * 4
assert gunicorn_app.cfg.threads == 1
assert gunicorn_app.cfg.timeout == 300
assert gunicorn_app.load() == app


Expand Down

0 comments on commit 3a0cdb8

Please sign in to comment.