A distributed task queue for asynchronous fractal image generation jobs using gRPC for interservice communication and Protobuf for serialization. The system implements a centralized coordinator pattern where a Python server manages task distribution through a priority queue while worker nodes concurrently handle fractal computation. The system features automatic task timeouts and resilience to worker failures.
The project demonstrates concepts widely applicable to distributed systems and data infrastructure, like asynchronous task queue management, service-oriented communication, and fault tolerance and resilience.
Below, you'll find exact outputs of these image generation jobs, generated by running client.py.
Mandelbrot Set
Julia Set
Coordinator initialized.
Coordinator running on port 50051!
Worker registered: worker-807144 at localhost
Worker registered: worker-ae4712 at localhost
Task submitted: a1aacdd7-eac6-417a-8a98-976c02cb32ee (Priority: 10)
Task submitted: ac71377d-048a-4cfe-80f8-9b8bf6a979e2 (Priority: 10)
Task submitted: e806e91e-8fab-47f1-8e89-19b976288020 (Priority: 10)
Task submitted: 553ef198-2b87-4543-9813-fb95bb0b5f25 (Priority: 10)
Sending task a1aacdd7-eac6-417a-8a98-976c02cb32ee to worker worker-807144
Task completed: a1aacdd7-eac6-417a-8a98-976c02cb32ee by worker-807144
Sending task ac71377d-048a-4cfe-80f8-9b8bf6a979e2 to worker worker-807144
Sending task e806e91e-8fab-47f1-8e89-19b976288020 to worker worker-ae4712
Task completed: ac71377d-048a-4cfe-80f8-9b8bf6a979e2 by worker-807144
...
coordinator.py- Central manager handling priority heap, worker registry, and task dispatchworker.py- Compute node that polls for tasks, generates Mandelbrot/Julia set chunks, and returns resultsclient.py- CLI tool for job submission and final image assemblyproto/task.proto- Protocol Buffer definition for service contracts and messages
High-performance inter-process communication:
- Serialization: Binary Protocol Buffers for efficient payload transfer
- Transport: HTTP/2 multiplexing via gRPC
- Methods like SubmitTask, GetTask, CompleteTask, RegisterWorker
Tasks are processed based on priority order using a min-heap structure:
- Heap Management: heapq-based queue for O(log n) insertion and extraction
- Ordering: Lower priority numbers execute first, and timestamps break ties
- Dataclass: Python @dataclass(order=True) enables native heap comparison
- grpcio, grpcio-tools, protobuf
- numpy, Pillow
(See requirements.txt)
Generate the gRPC stubs:
# Windows
mkdir generated
python -m grpc_tools.protoc -I./proto --python_out=./generated --grpc_python_out=./generated ./proto/task.protoStart Coordinator:
python coordinator.pyStart Workers (Multiple Terminals):
python worker.pySubmit Job:
# Generates a 1200x800 Mandelbrot set using 8 parallel regions
python client.py --mandelbrot --width 1200 --height 800 --regions 8
# Alternatively, generates a Julia set
python client.py --julia --width 1200 --height 800 --regions 8- Supported Types: Mandelbrot sets and Julia sets (with configurable constants)
- Parallelization: Image is sliced into horizontal bands (each worker computes one band)
- Output: Workers return raw byte arrays, and client reassembles them into a PNG file
- Registration: Workers generate a UUID and register capabilities on startup
- Polling: Pull-based model (GetTask) allows stateless load balancing
- Resilience: Failed or timed-out tasks are automatically re-injected into the priority queue
- Workers save result data to a local
.storagefolder instead of sending large payloads through gRPC - The client reads from these files and cleans them up after processing


