-
Notifications
You must be signed in to change notification settings - Fork 47
Description
Is this a support request?
Support Ticket #31907
Describe the bug
We are running a python flask app on a set of linux servers and in an AWS lambda. In our app, we create a ldclient
instance and try to close()
it when we are done. The ldclient.get().close()
function call didn't close all threads. The left over threads pile up and over time hit the system thread limit, because the application process is still running and is called on a new task. We start getting an error of RuntimeError: can't start new thread
In short, the bug is that the close()
function didn't close all threads. If set_config
get's called a 2nd time, as documented, a new ldclient
instance is created, the old one never completely goes away.
To reproduce
import atexit
import ldclient
import threading
def __set_launchdarkly_configuration(app):
ld_key = config.envars.get("LAUNCHDARKLY_SDK_KEY")
if ld_key:
ld_config = ldclient.config.Config(ld_key)
else:
ld_config = ldclient.config.Config("NOT_CONFIGURED", offline=True)
logger.warning(
"LAUNCHDARKLY_SDK_KEY is not set, feature flags will always return defaults"
)
ldclient.set_config(ld_config)
atexit.register(lambda: ldclient.get().close())
@atexit.register
def teardown_launchdarkly_configuration(exception=None):
logger.info(f"teardown launchdarkly_configuration, exception?: {exception}")
logger.info(f"Number of active threads: {threading.active_count()}")
# Call __set_launchdarkly_configuration function, ldclient.get(), and client.variation
Expected behavior
Ultimately, I expected the function ldclient.get().close()
to close all threads and release all ldclient
objects. I would expect my next ldclient.get().is_initialized()
to be false because I closed ldclient
so it should be in a state where I have to call set_config
I expected ldclient.set_config(ld_config)
to be smart enough to only create new instances if there doesn't exist an active instance or if the config values changed from the previous call. I know that ldclient.get()
enforces the singleton pattern, then I would expect `ldclient.set_config() to as well.
Maybe there should be something like a get_config
function to allow me to verify that the settings in code are the same as the active config and then I could re-use the existing ldclient
instead of creating a new one.
Logs
builtins.RuntimeError: can't start new thread
Traceback (most recent call last):
<removed>
File /function/ldclient/__init__.py, line 42, in set_config
{code_line}
File /function/ldclient/client.py, line 97, in __init__
{code_line}
File /function/ldclient/client.py, line 120, in _set_event_processor
{code_line}
File /function/ldclient/event_processor.py, line 396, in __init__
{code_line}
File /function/ldclient/repeating_timer.py, line 17, in start
{code_line}
File /usr/local/lib/python3.7/threading.py, line 852, in start
{code_line}
RuntimeError: can't start new thread
SDK version
We updated to version 7.5.1 and still saw this error. We tried v8.0.0 as well, same issue.
Language version, developer tools
Python 3.7
OS/platform
Docker container running python:3.7-slim
and Ubuntu 20.04
Additional context