Skip to content

Latest commit

Β 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧩 Python Multiprocessing Worker System (IPC-based)

πŸ“˜ Overview

πŸ“„ Read in Bahasa Indonesia

This project is an implementation of Inter-Process Communication (IPC) in Python using the multiprocessing module, where each worker process runs in parallel and communicates through Queues.

This structure is suitable for systems such as:

  • WhatsApp Client Instance Manager
  • Task Dispatcher (e.g., sending messages, fetching status, etc.)
  • Background Worker Engine

πŸš€ Core Concept: IPC (Inter-Process Communication)

IPC is a mechanism that allows independently running processes to communicate and exchange data.

🧠 Why IPC is Needed?

In multiprocessing:

  • Each process has its own memory space.
  • Variables between processes cannot be accessed directly.
  • A communication channel is needed (such as socket, pipe, or queue).

βš™οΈ Common IPC Methods in Python

Method Description Best For
multiprocessing.Queue Thread-safe FIFO queue for multiple processes Many workers
multiprocessing.Pipe Direct communication between two processes 1-to-1 connection
Manager / Value / Array Shared memory between processes Small data, simple sync
Socket / ZeroMQ Network communication between machines/processes Large-scale distributed systems

🧱 Project Structure

root_project/
β”‚
β”œβ”€β”€ workers/
β”‚   └── client_worker.py     # Single worker class running in separate process
β”‚
β”œβ”€β”€ utils/
β”‚   └── global_worker.py     # Main manager that creates, stores, and controls workers
β”‚
β”œβ”€β”€ controllers/
β”‚   β”œβ”€β”€ GetMessageController.py     # Example usage: fetch message
β”‚   └── SendMessageController.py    # Example usage: send message
β”‚
β”œβ”€β”€ main.py
β”œβ”€β”€ README_ID.md
└── README.md

πŸ”§ Main Components

1️⃣ ClientWorker

File: workers/client_worker.py

A subclass of multiprocessing.Process that runs as a separate process.
Its job is to read messages from queue_in, handle commands based on type, and return the result via queue_out.

from multiprocessing import Process, Queue

class ClientWorker(Process):
    def __init__(self, queue_in, queue_out, worker_id):
        super().__init__()
        self.queue_in = queue_in
        self.queue_out = queue_out
        self.worker_id = worker_id

    def run(self):
        print(f"[Worker-{self.worker_id}] started βœ…")
        while True:
            msg = self.queue_in.get()
            if msg is None:
                print(f"[Worker-{self.worker_id}] shutting down...")
                break

            msg_type = msg.get("type")
            data = msg.get("data")

            if msg_type == "get_message_byid":
                print(f"[Worker-{self.worker_id}] Fetch message for chatId={data.get('chatId')}")
                self.queue_out.put({
                    "from": self.worker_id,
                    "type": msg_type,
                    "result": "Fetched message"
                })
            elif msg_type == "send_message":
                print(f"[Worker-{self.worker_id}] Sending message:", data)
                self.queue_out.put({
                    "from": self.worker_id,
                    "type": msg_type,
                    "result": "Message sent"
                })
            else:
                print(f"[Worker-{self.worker_id}] Unknown message type:", msg_type)

2️⃣ ClientWorkerManager

File: utils/global_worker.py

Acts as a central manager that stores all worker instances (wa_1, wa_2, etc.) in a dictionary _instances.
Provides methods to:

  • Create a worker
  • Send message (send)
  • Receive result (receive)
  • Stop worker (stop)
from multiprocessing import Queue
from workers.client_worker import ClientWorker

class ClientWorkerManager:
    _instances = {}

    @classmethod
    def get(cls, worker_id):
        return cls._instances.get(worker_id)

    @classmethod
    def create(cls, worker_id):
        if worker_id in cls._instances:
            print(f"{worker_id} already exist in instances")
            return cls._instances[worker_id]

        queue_in = Queue()
        queue_out = Queue()
        worker = ClientWorker(queue_in, queue_out, worker_id)
        worker.start()

        cls._instances[worker_id] = {
            "queue_in": queue_in,
            "queue_out": queue_out,
            "process": worker
        }
        print(f"[Manager] Worker {worker_id} created.")
        return cls._instances[worker_id]

    @classmethod
    def send(cls, worker_id, type_, data=None):
        worker = cls.get(worker_id)
        if not worker:
            print(f"[Manager] ❌ Worker {worker_id} not found")
            return None

        msg = {"type": type_, "data": data or {}}
        worker["queue_in"].put(msg)
        print(f"[Manager] Sent to worker {worker_id}: {msg}")
        return True

    @classmethod
    def receive(cls, worker_id):
        worker = cls.get(worker_id)
        if worker and not worker["queue_out"].empty():
            return worker["queue_out"].get()
        return None

    @classmethod
    def stop(cls, worker_id):
        worker = cls.get(worker_id)
        if worker:
            worker["queue_in"].put(None)
            worker["process"].join()
            del cls._instances[worker_id]
            print(f"[Manager] Worker {worker_id} stopped.")

πŸ§ͺ Simulation Example

Controller A β€” Get Message by ID

from utils.global_worker import ClientWorkerManager
import time

worker_id = "wa_1"
ClientWorkerManager.create(worker_id)
ClientWorkerManager.send(worker_id, "get_message_byid", {"chatId": "abc123"})

time.sleep(1)
resp = ClientWorkerManager.receive(worker_id)
print("Response A:", resp)

Controller B β€” Send Message

from utils.global_worker import ClientWorkerManager
import time

worker_id = "wa_1"
ClientWorkerManager.create(worker_id)
ClientWorkerManager.send(worker_id, "send_message", {"text": "Hello from controller B!"})

time.sleep(1)
resp = ClientWorkerManager.receive(worker_id)
print("Response B:", resp)

⚑ Asynchronous Enhancement

To make communication non-blocking (without time.sleep), use asyncio + thread executor:

import asyncio

async def send_and_wait(worker_id, type_, data):
    ClientWorkerManager.send(worker_id, type_, data)
    while True:
        resp = ClientWorkerManager.receive(worker_id)
        if resp:
            return resp
        await asyncio.sleep(0.05)

πŸ” Benefits of This Architecture

βœ… Process isolation β€” each WhatsApp host has its own workspace
βœ… High scalability β€” dynamic worker creation
βœ… Data safety between processes β€” no shared memory interference
βœ… Fault tolerance β€” one worker crash doesn’t affect others
βœ… Flexible structure β€” easy to extend new command types


🧠 Comparison with Node.js

Aspect Node.js (child_process.fork()) Python (multiprocessing)
Model Single-threaded event-loop + child True multi-process
Communication .send() & .on("message") Queue or Pipe
Worker Scaling Easy for multiple child processes Requires queue management
Shared Memory Not directly supported Optional via Manager()

🏁 Conclusion

This structure builds an IPC-based worker system that is:

  • Safe and scalable
  • Suitable for multi-instance systems
  • Easy to integrate with controller or REST API layers

🧰 Requirements

  • Python 3.9+
  • No external libraries required (multiprocessing is built-in)

πŸ“„ License

MIT License Β© 2025


πŸ‘¨β€πŸ’» Author

Developed by Joel Binsar Jupiter
for experimental parallel processing and IPC in Python.

About

Python Multiprocessing Worker System (IPC-based)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages