diff options
| author | Markus Heiser <markus.heiser@darmarIT.de> | 2025-07-08 09:30:41 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-08 09:30:41 +0200 |
| commit | fe52290e653e969c959b3160c1a09f02e751efd2 (patch) | |
| tree | f06623fd9e8e1022798cfd2fa481662f8847dcdb | |
| parent | 6ff40356352e9f5b9c7f9c5d58ac2fc787455036 (diff) | |
[fix] calculator plugin: subrocess is not closed on timeout (#4983)
The issue was introduced in commit: edfbf1e
Problematic code::
def timeout_func(timeout, func, *args, **kwargs):
...
if not p.is_alive():
ret_val = que.get()
else:
logger.debug("terminate function after timeout is exceeded") # type: ignore
p.terminate()
p.join()
p.close()
The `logger` function in the `else` path is not defined. Was accidentally
removed in commit edfbf1e without providing an appropriate replacement.::
File "/usr/local/searxng/searx/plugins/calculator.py", line 216, in timeout_func
logger.debug("terminate function after timeout is exceeded") # type: ignore
^^^^^^
NameError: name 'logger' is not defined
The exception triggered by this prevents the `p.terminate()` from being
executed. As a result, the processes accumulate in memory (memory leak).
Related: https://github.com/searxng/searx-instances/discussions/708#discussioncomment-13688168
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
| -rw-r--r-- | searx/plugins/calculator.py | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index af44eea1e..5adaaaf22 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -40,6 +40,22 @@ class SXNGPlugin(Plugin): preference_section="general", ) + def timeout_func(self, timeout, func, *args, **kwargs): + que = mp_fork.Queue() + p = mp_fork.Process(target=handler, args=(que, func, args), kwargs=kwargs) + p.start() + p.join(timeout=timeout) + ret_val = None + # pylint: disable=used-before-assignment,undefined-variable + if not p.is_alive(): + ret_val = que.get() + else: + self.log.debug("terminate function (%s: %s // %s) after timeout is exceeded", func.__name__, args, kwargs) + p.terminate() + p.join() + p.close() + return ret_val + def post_search(self, request: "SXNG_Request", search: "SearchWithPlugins") -> EngineResults: results = EngineResults() @@ -72,7 +88,7 @@ class SXNGPlugin(Plugin): query_py_formatted = query.replace("^", "**") # Prevent the runtime from being longer than 50 ms - res = timeout_func(0.05, _eval_expr, query_py_formatted) + res = self.timeout_func(0.05, _eval_expr, query_py_formatted) if res is None or res[0] == "": return results @@ -200,21 +216,3 @@ def handler(q: multiprocessing.Queue, func, args, **kwargs): # pylint:disable=i except: q.put(None) raise - - -def timeout_func(timeout, func, *args, **kwargs): - - que = mp_fork.Queue() - p = mp_fork.Process(target=handler, args=(que, func, args), kwargs=kwargs) - p.start() - p.join(timeout=timeout) - ret_val = None - # pylint: disable=used-before-assignment,undefined-variable - if not p.is_alive(): - ret_val = que.get() - else: - logger.debug("terminate function after timeout is exceeded") # type: ignore - p.terminate() - p.join() - p.close() - return ret_val |