pythonmultithreadingsubprocessconcurrent.futures

I am using subprocess.Popen class with threading and it is not working for me


I have following files:

ping.py:

from utilities.env import PACKET_COUT, PING_TIME, MAX_WORKERS_COUNT
from utilities.cmds import create_ping_cmd
from subprocess import Popen, PIPE, DEVNULL, TimeoutExpired
from re import findall
from concurrent.futures import ThreadPoolExecutor


MAX_PING_TIME = float(PACKET_COUT) * (float(PING_TIME))
ping_cmd = create_ping_cmd()

def check_ping_process(ping_process):
    ping_result = {}
    try:
        out = ping_process.communicate(timeout=MAX_PING_TIME)[0]
        is_successes = findall("TTL", out)
        if ping_process.returncode == 0 and is_successes:
            return True
        else:
            return False
    except TimeoutExpired:
        ping_process.kill()
        return False


def ping_ip(ip):
    ping_cmd.append(ip)
    ping_process = Popen(
        ping_cmd,
        stdout=PIPE,
        stderr=DEVNULL,
        text=True
    )
    result = check_ping_process(ping_process)
    return result


def ping_ip_list(ip_list):
    ping_results = []
    with ThreadPoolExecutor(max_workers=MAX_WORKERS_COUNT) as executor:
        results = executor.map(ping_ip, ip_list)
        for ip, result in zip(ip_list, results):
            print({ip, result})
            ping_results.append({ip, result})
    return ping_results

main.py:

from ping import ping_ip_list


ip_list = [
    '192.168.0.100',
    '192.168.0.1',
    '192.168.0.104',
    '192.168.0.124',
    '192.168.0.103'
]
def monitor_network_devices(ip_list):
    results = ping_ip_list(ip_list)

monitor_network_devices(ip_list)

The goal of the program is find out if network device is pingable or not. I am running main.py file, which is giving wrong results. I tried debug, it is appeared the problem with threads, but I cannot resolve it.

Any help would be greatly appreciated


Solution

  • A few observations

    With that, here is my proposed solution

    # ping.py
    import logging
    import subprocess
    from concurrent.futures import ThreadPoolExecutor
    
    logging.basicConfig(
        level=logging.DEBUG,
        format="%(asctime)s | %(levelname)s | %(threadName)-15s | %(funcName)-18s | %(message)s",
    )
    
    
    def ping_ip(ip):
        ping_command = ["ping", "-c1", ip]
        logging.debug("Execute command %r", ping_command)
        completed_process = subprocess.run(
            ping_command,
            text=True,
            capture_output=True,
            check=False,
        )
        success = completed_process.returncode == 0
        logging.debug("%s -> %r", ip, success)
        return success
    
    
    def ping_ip_list(ip_list):
        with ThreadPoolExecutor() as executor:
            out = dict(zip(ip_list, executor.map(ping_ip, ip_list)))
        return out