You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I recently encountered this error by chance when looking at my logs. I checked the last week's worth of logs and it looks like it had only occurred once. The relevant lines are:
20/04/24 02:17:02 - DEBUG - TwitchChannelPointsMiner.classes.WebSocketsPool - [on_message]: #0 - Received: {"type":"MESSAGE","data":{"topic":"video-playback-by-id.###","message":"{\"server_time\":1713575822,\"type\":\"stream-down\"}"}}
20/04/24 02:17:02 - INFO - TwitchChannelPointsMiner.classes.Chat - [stop]: Leave IRC Chat: ###
20/04/24 02:17:02 - ERROR - TwitchChannelPointsMiner.classes.Chat - [start]: Exception raised: file descriptor cannot be a negative integer (-1). Thread is active: True
// above line repeated 195 times
20/04/24 02:17:02 - INFO - TwitchChannelPointsMiner.classes.entities.Streamer - [set_offline]: Streamer(username=###, channel_id=###, channel_points=###) is Offline!
Looking through the code, in response to a stream-down message the miner will:
Call Streamer.set_offline() for the appropriate Streamer
This sets Streamer.is_online = False
Then it calls Streamer.toggle_chat()
Assuming Streamer.settings.chat is ChatPresence.ONLINE it will then call Streamer.leave_chat() (Incidentally this is likely why the issue doesn't show up for ChatPresence.ALWAYS)
This calls self.irc_chat.stop() which is a method on ThreadChat in Chat.py
This ends up calling self.chat_irc.die() which is a method on ClientIRC:
I believe this is where a race condition happens. This final method sets __active to False only after calling disconnect on the underlying connection. Disconnect ends up invalidating the underlying Socket and I think the File Descriptor will be -1 for a closed Socket, however I'm no expert on this. This is likely the -1 in the error message.
At the same time as this is happening we also have ClientIRC.start. In there is the while loop that processes the IRC connection:
f"Exception raised: {e}. Thread is active: {self.__active}"
)
As previously noted by @rdavydov, that call to logger.error is the source of the error we see in the log. So the Exception that caused it must have come from that try block.
Since these 2 things (processing the connection and responding to stream-down) are happening in 2 different Threads it's entirely possible, albeit unlikely, for execution to change Threads mid-disconnection after the socket becomes invalid but before it sets the __active state. And since this while loop uses that state to determine whether to continue trying to process the connection, it could end up trying to read from a closed socket.
I believe a simple fix to this is to set __active = False prior to starting the disconnection, just swap those 2 lines in ClientIRC.die:
I recently encountered this error by chance when looking at my logs. I checked the last week's worth of logs and it looks like it had only occurred once. The relevant lines are:
This is the code that processes that message:
Twitch-Channel-Points-Miner-v2/TwitchChannelPointsMiner/classes/WebSocketsPool.py
Lines 233 to 235 in 62c01c4
Looking through the code, in response to a
stream-down
message the miner will:Streamer.set_offline()
for the appropriate StreamerStreamer.is_online = False
Streamer.toggle_chat()
Streamer.settings.chat
isChatPresence.ONLINE
it will then callStreamer.leave_chat()
(Incidentally this is likely why the issue doesn't show up forChatPresence.ALWAYS
)self.irc_chat.stop()
which is a method onThreadChat
in Chat.pyself.chat_irc.die()
which is a method onClientIRC
:Twitch-Channel-Points-Miner-v2/TwitchChannelPointsMiner/classes/Chat.py
Lines 49 to 51 in 62c01c4
I believe this is where a race condition happens. This final method sets
__active
toFalse
only after calling disconnect on the underlying connection. Disconnect ends up invalidating the underlying Socket and I think the File Descriptor will be -1 for a closed Socket, however I'm no expert on this. This is likely the -1 in the error message.At the same time as this is happening we also have
ClientIRC.start
. In there is the while loop that processes the IRC connection:Twitch-Channel-Points-Miner-v2/TwitchChannelPointsMiner/classes/Chat.py
Lines 40 to 47 in 62c01c4
As previously noted by @rdavydov, that call to
logger.error
is the source of the error we see in the log. So the Exception that caused it must have come from thattry
block.Since these 2 things (processing the connection and responding to
stream-down
) are happening in 2 different Threads it's entirely possible, albeit unlikely, for execution to change Threads mid-disconnection after the socket becomes invalid but before it sets the__active
state. And since this while loop uses that state to determine whether to continue trying to process the connection, it could end up trying to read from a closed socket.I believe a simple fix to this is to set
__active = False
prior to starting the disconnection, just swap those 2 lines inClientIRC.die
:That should allow the while loop to exit early. It doesn't look like anything else relies on
__active
so there should be no other side-effects.Originally posted by @mpforce1 in #250 (comment)
The text was updated successfully, but these errors were encountered: