Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Python] Generated code is out of contract - application hangs indefinitely #9991

Open
gaborbernat opened this issue Jan 16, 2020 · 5 comments · May be fixed by #10002
Open

[Python] Generated code is out of contract - application hangs indefinitely #9991

gaborbernat opened this issue Jan 16, 2020 · 5 comments · May be fixed by #10002

Comments

@gaborbernat
Copy link

gaborbernat commented Jan 16, 2020

The generated code snippet from - https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/python/api_client.mustache#L73 is not allowed:

    def __del__(self):
        if self._pool is not None:
            self._pool.close()
            self._pool.join()

The very simple program of creating a global client, and then just exiting will hang indefinitely on Python3.8. Initially raised as CPython bug under https://bugs.python.org/issue39360, but @pablogsal (core CPython developer) investigated and concluded that this way of cleaning up pools is not supported. Instead one should either allow the user to close or if the user did not do the generated code should do by registering https://docs.python.org/3.8/library/atexit.html callbacks.

The code in question seemed to be added within #6396 by @tuxbotix with approvers being @scottrw93 @taxpon @frol @mbohlool, so tagging them for context.

@pablogsal
Copy link

pablogsal commented Jan 16, 2020

To clarify: the reason is "not supported" is because the interpreter does not promise that __del__ with being even called or in what situations that will happen. In particular, there are multiple locks and threads that can hang if __del__ is called during finalization or from the gc. From https://docs.python.org/3/reference/datamodel.html#object.__del__:

Warning Due to the precarious circumstances under which __del__() methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed to sys.stderr instead. In particular:
* __del__() can be invoked when arbitrary code is being executed, including from any arbitrary thread. If __del__() needs to take a lock or invoke any other blocking resource, it may deadlock as the resource may already be taken by the code that gets interrupted to execute __del__().

* __del__() can be executed during interpreter shutdown. As a consequence, the global variables it needs to access (including other modules) may already have been deleted or set to None. Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called.

This worked on Python <3.7 in a very flaky way: the pool used a busy loop (now it uses a more robust system of sentinels) and the sleep in that busy loop was big enough that make the pool more likely to be consistent in this scenario, but technically is the same problem. Indeed, reducing the timeout of the busy loop makes it hang as well in 3.7 or older.

@fabianvf
Copy link

We're seeing indefinite hangs in the __del__ method in the Kubernetes Python client that seem consistent with this issue

fabianvf added a commit to fabianvf/swagger-codegen that referenced this issue Jan 22, 2020
This removes the `__del__` function from the generated Python client,
and replaces it with a `cleanup` function. When a ThreadPool is created,
the cleanup function is registered with the `atexit` module.

This fixes swagger-api#9991, where the API client could hang indefinitely at
garbage collection.
@fabianvf fabianvf linked a pull request Jan 22, 2020 that will close this issue
4 tasks
fabianvf added a commit to fabianvf/swagger-codegen that referenced this issue Jan 22, 2020
This removes the `__del__` function from the generated Python client,
and replaces it with a `cleanup` function. When a ThreadPool is created,
the cleanup function is registered with the `atexit` module.

This fixes swagger-api#9991, where the API client could hang indefinitely at
garbage collection.
fabianvf added a commit to fabianvf/swagger-codegen that referenced this issue Jan 23, 2020
This removes the `__del__` function from the generated Python client,
and replaces it with a `cleanup` function. When a ThreadPool is created,
the cleanup function is registered with the `atexit` module.

This fixes swagger-api#9991, where the API client could hang indefinitely at
garbage collection.
@noamgat
Copy link

noamgat commented Nov 18, 2020

Was this ever merged?

@fabianvf
Copy link

@noamgat it was merged to the openapi repo, never here

@MasterSergius
Copy link

Is there any update on this issue? It hangs still, here's my code to check:

from swagger_client import ApiClient, Configuration, UserApi

configuration = Configuration()
configuration.host = host
configuration.api_key['Authorization'] = token
configuration.api_key_prefix['Authorization']='Bearer'


client = UserApi(ApiClient(configuration))

for item in client.list_users():
    print(item)

# and it can't exit the script, hangs indefinitely

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants