Add command to kill all children processes spawned by cmdthread

Additionally, a maximum send queue length was added to avoid something like `cat /dev/urandom` from being a massive memory hog and causing OOM.

Because output is read from the process and added to the message queue in real time, this could lead to infinite memory usage without it.
This commit is contained in:
Jordyn 2026-03-14 22:03:03 -05:00
commit ac6560e680
2 changed files with 25 additions and 3 deletions

22
main.py
View file

@ -19,7 +19,7 @@ class Server():
# Setup the IRC related things such as user details and prefixes # Setup the IRC related things such as user details and prefixes
# This function also sets up the threading events and queues # This function also sets up the threading events and queues
def __init__(self, realname, nickname, channels, command_prefix = "$!", bot_prefix = "$$", opper_nicknames = []): def __init__(self, realname, nickname, channels, command_prefix = "$!", bot_prefix = "$$", opper_nicknames = [], message_queue_max_size = 512):
print(f"[SERVER/MAINTHREAD] Using Server() on Python3 PID {os.getpid()}") print(f"[SERVER/MAINTHREAD] Using Server() on Python3 PID {os.getpid()}")
self.realname = realname self.realname = realname
self.nickname = nickname self.nickname = nickname
@ -35,8 +35,11 @@ class Server():
# Used to signal threads to shutdown # Used to signal threads to shutdown
self._going_down = threading.Event() self._going_down = threading.Event()
# Used to signal command thread to kill the children process
self._kill_cmd = threading.Event()
# Queue used for IRC server send() calls # Queue used for IRC server send() calls
self._send_q = queue.Queue() self._send_q = queue.Queue(maxsize = message_queue_max_size)
# Rate limiting variables # Rate limiting variables
# Used so it can be quired by IRC # Used so it can be quired by IRC
@ -198,6 +201,13 @@ class Server():
proc.kill() proc.kill()
break break
# Check for kill children flag
if self._kill_cmd.is_set():
print(f"[CMDTHREAD] Quitting due to bot command!")
proc.kill()
self._kill_cmd.clear()
break
# Read a line up to max_data_len # Read a line up to max_data_len
# Replace invalid chars with escape sequences # Replace invalid chars with escape sequences
line = proc.stdout.readline(max_data_len) line = proc.stdout.readline(max_data_len)
@ -410,6 +420,14 @@ class Server():
self.privmsg(msg["target_channel"], f"Clearing sendq of size {self._send_q.qsize()}", bypass_q = True) self.privmsg(msg["target_channel"], f"Clearing sendq of size {self._send_q.qsize()}", bypass_q = True)
self._oneshot_thread(self._clear_sendq) self._oneshot_thread(self._clear_sendq)
def _cmd_killcmd(self, msg):
print("[RECVTHREAD] Signaling CMDTHREAD(s) to kill their children!")
self._kill_cmd.set()
# Also clear the sendq as this command will typically be used when doing
# something such as catting /dev/urandom
self._oneshot_thread(self._clear_sendq)
if __name__ == "__main__": if __name__ == "__main__":
serv = Server(**config.user, **config.bot) serv = Server(**config.user, **config.bot)
serv.connect(**config.server) serv.connect(**config.server)

View file

@ -15,5 +15,9 @@ server = {
bot = { bot = {
"command_prefix": "$!", "command_prefix": "$!",
"bot_prefix": "$$", "bot_prefix": "$$",
"opper_nicknames": ["nicknamehere"] "opper_nicknames": ["nicknamehere"],
# 512 messages * 512 bytes maximum per message = 262144 bytes max message queue size
# Adjust for RAM needs to avoid cat /dev/urandom from causing OOM
"message_queue_max_size": 512
} }