Distributed system that processes messages and turns them into binary code. It was made using Golang, TDD, Clean Architecture and following scalability principles.
- Golang
- WebSocket (real-time updates)
- RabbitMQ (async queueing)
- GraphQL (API Gateway)
- gRPC (service-to-service)
- Postgres (persistent storage)
- Kubernetes (orchestration)
Below is the main architecture diagram showing the services and the message flow.
This repository includes a few screenshots captured from the demo environment to help visualise the system:
-
Client UI —
docs/ui.png
The client web UI used to submit messages, inspect recent tasks and see live WebSocket events. -
Observability (Grafana) —
docs/grafana.png
Grafana dashboard showing service metrics (CPU, goroutines, request rates, etc.). Useful to verify deployment health. -
Kubernetes / cluster view —
docs/k8s.png
A screenshot with kubectloutput showing running pods and services used in the demo. -
Test coverage snapshot —
docs/test-coverage.png
Coverage report snapshot used during development and CI checks.
The project implements a small distributed pipeline. High level flow:
- Client sends
messages[]to the API Gateway using GraphQL. - API Gateway streams messages to the Task Service (gRPC).
- Task Service inserts tasks into Postgres and writes an unprocessed outbox event.
- Event Publisher polls unprocessed events and publishes them to RabbitMQ (queue flow).
- A processing worker consumes the queue, reads the task payload, converts the message to binary and streams the processed result back to the Task Service (gRPC callback).
- Task Service marks the task as processed and writes a processed outbox event.
- Event Publisher publishes processed events to a fanout exchange which the WebSocket Service consumes.
- WebSocket Service pushes
Task{ID, BinaryCode}to connected clients.
See the detailed section below for contracts and use cases.
api_gateway/internal/entities.Task:ID,Message,BinaryCode,CreatedAt,UpdatedAttask_service/internal/entities.Task:ID,Message,BinaryCode,CreatedAt,UpdatedAtprocessing_service/internal/entities.Task:ID,BinaryCodewebsocket_service/internal/entities.Task:ID,BinaryCode
- Task IDs are opaque string identifiers generated by
IDGenerator. CreatedAtandUpdatedAtare represented as strings at service boundaries in the codebase.- If persisted in Postgres, timestamp fields should be mapped to
timestamp/timestamptz. BinaryCodeis empty before processing and set afterProcessTaskUseCaseruns.
- GraphQL: client ⇢ API Gateway
- gRPC: API Gateway ⇢ Task Service; Processing Service ⇢ Task Service (callback)
- Postgres: Task Service storage + outbox table
- RabbitMQ: Event Publisher → queue & fanout flows
- WebSocket: WebSocket Service → client
This is the detailed chain of usecases and transports the system implements.
Use case: SendTaskToProcessUseCase
Input example:
&SendTaskToProcessInput{ Messages: []string{"hello", "world"} }Boundary method called: TaskProcessorInterface.SendTaskToProcess(messages []string)
Transport: TaskService.ReceiveTaskToProcess(stream ReceiveTaskToProcessRequest) (gRPC client-streaming)
Use case: ReceiveTaskToProcessUseCase — inserts a task row and writes an unprocessed outbox event.
Use case: ProcessUnprocessedEventsUseCase — polls outbox, publishes queue messages (RabbitMQ)
Use case: ProcessTaskUseCase — reads task by ID, converts message → BinaryCode, sends processed payload back via gRPC
Use case: ReceiveProcessedTaskUseCase — marks task as processed and writes processed outbox event
Use case: SendProcessedEventsUseCase — publishes processed events to fanout exchange
Use case: SendProcessedTasksUseCase — pushes Task{ID, BinaryCode} to clients
- The repository contains generated gRPC stubs in each service; if you change proto files, regenerate the stubs.
- For a stronger contract, consider switching the processed-task stream to a structured message (e.g.
ProcessedTask { id, binary_code }) instead ofrepeated string. - Add DB migrations (DDL) for
tasksandoutbox_eventsif you plan to bootstrap a fresh environment.
Douglas Volcato — https://github.com/DouglasVolcato
