Задать вопрос
@ArtemMik
Python

Как выключить subprocess по pid?

столкнулся с проблемой завершения subprocess

У меня есть один главный бот, который запускает много дочерних ботов (система подписки в боте главном работает), когда подписка истекла, то дочерний бот должен выключится, при старте всех дочерних ботов я сохраняю их process.pid, чтобы потом по нему можно было выключить, но не получается сколько не пробовал

Код:

import os

from bot_functions import *
import subprocess
from threading import Thread, Lock
import sqlite3


def get_db_connection():
    return sqlite3.connect('users_malling.db')


def add_process(process, user_id):
    conn = get_db_connection()
    with conn:
        cur = conn.cursor()
        process_pid = process.pid # Get the PID of the process
        print(process_pid, user_id)
        cur.execute('INSERT INTO processes (process, user_id) VALUES (?, ?)', (int(process_pid), user_id))
        conn.commit()

def get_all_bot_tokens():
    tokens = []
    user_ids = []
    cur.execute("SELECT bot_token, user_id, banned FROM users WHERE bot_token IS NOT NULL")
    rows = cur.fetchall()
    for row in rows:
        if row[2] == 0:
            tokens.append(row[0])
            user_ids.append(row[1])
    return tokens, user_ids



lock = Lock()
bot_processes = {}


def start_bot(bot_token, user_id):
    db_name = f"user_{user_id}.db"
    command = f"python users_bots/bot_functions.py --token {bot_token} --db {db_name} --user {user_id}"
    process = subprocess.Popen(command, shell=True)
    proccess_pid = process.pid
    add_process(process=process, user_id=user_id)
    log_file_path = f"user_{user_id}_bot_output.txt"
    logging.info(f"Logging output to {log_file_path}")
    print(f"Added process for user_id {user_id} to bot_processes.")
    print(bot_processes)

def stop_bot_process(user_id):
    """Остановить процесс бота по user_id."""
    conn = get_db_connection()
    with conn:
        cur = conn.cursor()
        cur.execute('SELECT process FROM processes WHERE user_id = ?', (user_id,))
        result = cur.fetchone()

    if result:
        process_pid = int(result[0])
        print(f"Retrieved process PID {process_pid} for user_id {user_id}.")

        try:
            # Using psutil to terminate the process
            process = psutil.Process(process_pid)
            print(f"Terminating process with PID {process_pid} for user_id {user_id}.")
            process.terminate()  # Gracefully terminate the process
            os.kill(process_pid, signal.CTRL_C_EVENT)
            process.wait()  # Wait for the process to terminate
            print(f"Process with PID {process_pid} terminated.")

            with lock:
                if user_id in bot_processes:
                    del bot_processes[user_id]  # Remove the process from the dictionary

            logging.info(f"Bot with user_id {user_id} stopped.")
            print(f"Stopped bot process for user_id {user_id}.")
        except psutil.NoSuchProcess:
            logging.warning(f"No running bot found with PID {process_pid} for user_id {user_id}.")
            print(f"No running bot found for PID {process_pid} and user_id {user_id}.")
        except psutil.AccessDenied:
            logging.error(f"Access denied when trying to terminate process PID {process_pid}.")
            print(f"Access denied when trying to terminate process PID {process_pid}.")
        except Exception as e:
            logging.error(f"Error terminating process PID {process_pid}: {e}")
            print(f"Error terminating process PID {process_pid}: {e}")
    else:
        logging.warning(f"No process found in the database for user_id {user_id}.")
        print(f"No process found in the database for user_id {user_id}.")

def start_all_bots():
    tokens, user_ids = get_all_bot_tokens()
    for bot_token, user_id in zip(tokens, user_ids):
        cur.execute("UPDATE users SET active = ? WHERE user_id = ?", (1, user_id))
        db.db.commit()
        thread = Thread(target=start_bot, args=(bot_token, user_id))
        thread.start()


if __name__ == "__main__":
    start_all_bots()
    executor.start_polling(dp, on_startup=on_startup, skip_updates=False)
  • Вопрос задан
  • 67 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
@nemolayn
Создатель бота Nemo
Обычный kill при shell не подойдет, попробуйте так:
os.killpg(process_pid, signal.SIGTERM)
Или можно еще попробовать так:
from subprocess import check_call

check_call("TASKKILL /F /PID {pid} /T".format(pid=process_pid))
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы