Skip to content

Commit ac1f652

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 b4e4b59 commit ac1f652

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

cassandra/io/eventletreactor.py

Lines changed: 10 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

@@ -162,6 +165,8 @@ def handle_write(self):
162165
next_msg = self._write_queue.get()
163166
self._socket.sendall(next_msg)
164167
except socket.error as err:
168+
if self.is_closed or self.is_defunct:
169+
return
165170
log.debug("Exception during socket send for %s: %s", self, err)
166171
self.defunct(err)
167172
return # Leave the write loop
@@ -174,6 +179,8 @@ def handle_read(self):
174179
buf = self._socket.recv(self.in_buffer_size)
175180
self._iobuf.write(buf)
176181
except socket.error as err:
182+
if self.is_closed or self.is_defunct:
183+
return
177184
log.debug("Exception during socket recv for %s: %s",
178185
self, err)
179186
self.defunct(err)
@@ -185,6 +192,8 @@ def handle_read(self):
185192
self.process_io_buffer()
186193
else:
187194
log.debug("Connection %s closed by server", self)
195+
self.last_error = ConnectionShutdown(
196+
"Connection to %s was closed by server" % self.endpoint)
188197
self.close()
189198
return
190199

0 commit comments

Comments
 (0)