Skip to content

Commit d30278c

Browse files
committed
Fix EventletConnection close() race causing EBADF errors (#614)
EventletConnection.close() uses blocking kill() which mostly prevents races, but if close() is called from a non-eventlet thread the greenthread may not be interrupted as expected. - Add is_closed/is_defunct guards in handle_read() and handle_write() error paths to silently exit during shutdown - Set last_error in close() when connected_event is not yet set to prevent factory() from returning a dead connection - Set last_error on server-initiated close (EOF) in handle_read()
1 parent f348637 commit d30278c

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

cassandra/io/eventletreactor.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ def close(self):
148148
msg = "Connection to %s was closed" % self.endpoint
149149
if self.last_error:
150150
msg += ": %s" % (self.last_error,)
151-
self.error_all_requests(ConnectionShutdown(msg))
151+
shutdown_exc = ConnectionShutdown(msg)
152+
self.error_all_requests(shutdown_exc)
153+
if not self.connected_event.is_set():
154+
self.last_error = shutdown_exc
152155
# don't leave in-progress operations hanging
153156
self.connected_event.set()
154157

@@ -185,6 +188,8 @@ def handle_read(self):
185188
self.process_io_buffer()
186189
else:
187190
log.debug("Connection %s closed by server", self)
191+
self.last_error = ConnectionShutdown(
192+
"Connection to %s was closed by server" % self.endpoint)
188193
self.close()
189194
return
190195

0 commit comments

Comments
 (0)