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

PythonParser vs HiredisParser on_disconnect behavior #1085

Closed
popravich opened this issue Nov 21, 2018 · 6 comments
Closed

PythonParser vs HiredisParser on_disconnect behavior #1085

popravich opened this issue Nov 21, 2018 · 6 comments

Comments

@popravich
Copy link
Contributor

PythonParser's on_disconnect implementation is inconsistent with HiredisParser implementation (or vice versa):

class PythonParser(...):
    def on_disconnect(self):
        "Called when the socket disconnects"
        if self._sock is not None:
            self._sock.close()
            self._sock = None
        if self._buffer is not None:
            self._buffer.close()
            self._buffer = None
        self.encoder = None

and

class HiredisParser(...):
    def on_disconnect(self):
        self._sock = None
        self._reader = None
        self._next_response = False

Why does the PythonParser closes the _sock object?
By doing this the subsequent shutdown() and close() in Connection.disconnect does not make any sense, in fact it shutdown on closed socket raises error which is ignored.

I can submit a PR but please tell me what place to fix? (HiredisParser/PythonParser/shutdown)

PS: this issue causes other issues in other repos (celery/kombu#954, celery/celery#3898)

@theodesp
Copy link
Contributor

theodesp commented Dec 3, 2018

I suspect it's because it's not covered with test cases. Feel free to provide a PR with coverage that does not break compatibility.

@popravich
Copy link
Contributor Author

I'm sorry, but I don't understand, what a PR should cover?
Just add a test to show that PythonParser closes the Connection's socket and HiredisParser does not?

@andymccurdy
Copy link
Contributor

You're right, the inconsistency is an error. From briefly scanning this, it seems wrong that PythonParser is closing the socket in on_disconnect.

Are you proposing that we simply remove the self._sock.close() from PythonParser.on_disconnect?

@popravich
Copy link
Contributor Author

Are you proposing that we simply remove the self._sock.close() from PythonParser.on_disconnect?

Yes, this, at least, will make "on disconnect" behaviour similar regardless of parser used in connection.

@andymccurdy
Copy link
Contributor

@popravich I agree. If you want to create a PR that removes the socket.close() I'll gladly merge it.

I'm also open to addressing the fork issues you're seeing in kombu/celery. Just let me know.

popravich added a commit to popravich/redis-py that referenced this issue Jan 3, 2019
…onnect

implementation/behavior (related to redis#1085).

When hiredis is installed and HiredisParser is used (implicitly),
connection can not be securily shared between process forks.
@popravich
Copy link
Contributor Author

Hi, @andymccurdy,
I've just updated related PR with the fix, please take a look.

andymccurdy added a commit that referenced this issue Feb 1, 2019
Sometimes a process with an active connection to Redis forks and creates
child processes taht also want to talk to Redis. Prior to this change there
were a number of potential conflicts that could cause this to fail.

Retrieving a connection from the pool and releasing a connection back
to the pool check the current proceeses PID. If it's different than the
PID that created the pool, reset() is called to get a fresh set of connections
for the current process. However in doing so, pool.disconnect() was caused
which closes the file descriptors that the parent may still be using. Further
when the available_connections and in_use_connections lists are reset, all of
those connections inherited from the parent are GC'd and the connection's
`__del__` was called, which also closed the socket and file descriptor.

This change prevents pool.disconnect() from being called when a pid is changed.
It also removes the `__del__` destructor from connections. Neither of these
are necessary or practical. Child processes still reset() their copy of the
pool when first accessed causing their own connections to be created.

`ConnectionPool.disconnect()` now checks the current process ID
so that a child or parent can't disconnect the other's connections.

Additionally, `Connection.disconnect()` now checks the current process ID
and only calls `socket.shutdown()` if `disconnect()` is called by the same
process that created the connection. This allows for a child process that
inherited a connection to call `Connection.disconnect()` and not shutdown
the parent's copy of the socket.

Fixes #863
Fixes #784
Fixes #732
Fixes #1085
Fixes #504
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

No branches or pull requests

3 participants