kaizendorks / pymongo_inmemory

A mongo mocking library with an ephemeral MongoDB running in memory.
MIT License
40 stars 13 forks source link

is it normal for `client.close()` to take 30 seconds? #55

Closed jbkoh closed 1 year ago

jbkoh commented 2 years ago

Hi there, thanks for the great project! I finally found a project that I can use for my unit testing!

In the process, I realized that each client.close() takes about 30 seconds. Each database has a single document. I would like to use it as a set of data set as a fixture with a clean state of the in memory database. So, I will instantiate it and close it many times for unit testing.

Is the 30 seconds delay something configurable or inherent to the design?

Any advice would be appreciated. Thanks!

ekarademir commented 2 years ago

Hi @jbkoh I haven't done any timed tests, however the close process basically does a bit of checking to make sure all the created processes are killed. Maybe that is causing 30 second delay. But there is no set delay for anything.

PetrF0X commented 1 year ago

Hi @jbkoh I just noticed the same problem. I followed the client.close() with an attached debugger and found that the 30 second delay occurs in pymongo, not pymongo_inmemory. It happens when pymongo client tries to close open sessions and it can't reach the server - pymongo tries to reach the server for the 30 seconds before it times out.

I think I found the problem:

Have a look at pymongo_inmemory's _pim.py:

class MongoClient(pymongo.MongoClient):
    def __init__(self, host=None, port=None, **kwargs):
        self._mongod = Mongod()
        self._mongod.start()
        super().__init__(self._mongod.connection_string, **kwargs)

    def close(self):
        self._mongod.stop()
        super().close()

The thing is the mongod process is stopped before the pymongo sessions are attempted to be closed in super().close(). If we swap the two commands in the close function, the sessions will be closed first and then the server will be stopped. There won't be any 30 seconds delay because we don't hit the timeout when trying to reach a stopped server.

Additionally, this may only be a problem on a Windows machine. Here's the error:

127.0.0.1:27018: [WinError 10061] No connection could be made because the target machine actively refused it, Timeout: 30s, Topology Description: <TopologyDescription id: 635c15e6da022e996245aa7b, topology_type: Single, servers: [<ServerDescription ('127.0.0.1', 27018) server_type: Unknown, rtt: None, error=AutoReconnect('127.0.0.1:27018: [WinError 10061] No connection could be made because the target machine actively refused it')>]>

What do you think @ekarademir?

jbkoh commented 1 year ago

Thanks for digging in @PetrF0X ! I support the idea as it makes more sense to close the client first (self) before closing the server (_mongod)

ekarademir commented 1 year ago

This is a very good dig @PetrF0X. If you want to create a PR for it we can get it out of the door and create a new release.

ekarademir commented 1 year ago

Hopefully the latest merge solves this problem. Feel free to open again if it doesn't. I'll create a release in few mins.