@@ -176,8 +176,13 @@ def connect(self) -> None:
176176
177177 def disconnect (self ) -> None :
178178 if self .sock is not None :
179- self .sock .close ()
180- self .sock = None
179+ with self .sock_send_lock :
180+ with self .sock_receive_lock :
181+ # Synchronize before closing this instance's socket
182+ self .sock .close ()
183+ self .sock = None
184+ # After this, all operations using self.sock will be skipped
185+
181186 self .logger .info (
182187 f"The connection has been closed (session id: { self .session_id } )"
183188 )
@@ -198,7 +203,13 @@ def ping(self, payload: Union[str, bytes] = "") -> None:
198203 )
199204 data = _build_data_frame_for_sending (payload , FrameHeader .OPCODE_PING )
200205 with self .sock_send_lock :
201- self .sock .send (data )
206+ if self .sock is not None :
207+ self .sock .send (data )
208+ else :
209+ if self .ping_pong_trace_enabled :
210+ self .logger .debug (
211+ "Skipped sending a ping message as the underlying socket is no longer available."
212+ )
202213
203214 def pong (self , payload : Union [str , bytes ] = "" ) -> None :
204215 if self .trace_enabled and self .ping_pong_trace_enabled :
@@ -210,7 +221,13 @@ def pong(self, payload: Union[str, bytes] = "") -> None:
210221 )
211222 data = _build_data_frame_for_sending (payload , FrameHeader .OPCODE_PONG )
212223 with self .sock_send_lock :
213- self .sock .send (data )
224+ if self .sock is not None :
225+ self .sock .send (data )
226+ else :
227+ if self .ping_pong_trace_enabled :
228+ self .logger .debug (
229+ "Skipped sending a pong message as the underlying socket is no longer available."
230+ )
214231
215232 def send (self , payload : str ) -> None :
216233 if self .trace_enabled :
@@ -222,7 +239,17 @@ def send(self, payload: str) -> None:
222239 )
223240 data = _build_data_frame_for_sending (payload , FrameHeader .OPCODE_TEXT )
224241 with self .sock_send_lock :
225- self .sock .send (data )
242+ try :
243+ self .sock .send (data )
244+ except Exception as e :
245+ # In most cases, we want to retry this operation with a newly established connection.
246+ # Getting this exception means that this connection has been replaced with a new one
247+ # and it's no longer usable.
248+ # The SocketModeClient implementation can do one retry when it gets this exception.
249+ raise SlackClientNotConnectedError (
250+ f"Failed to send a message as the connection is no longer active "
251+ f"(session_id: { self .session_id } , error: { e } )"
252+ )
226253
227254 def check_state (self ) -> None :
228255 try :
0 commit comments