A microservices-based calculator system built using Go (gRPC) and Node.js (REST). It uses Kafka for message communication with outbox pattern. also Observability and Moitoring using Prometheus and Grafana.
- Exposes calculator operations (Add, Subtract, Multiply, Divide) via gRPC.
- Stores requests in a PostgreSQL-backed outbox table.
- Polls the outbox table and publishes events to Kafka.
- Periodically reads events from the outbox table.
- Publishes events to a Kafka topic (
calculations
).
- Consumes messages from the
calculations
topic. - Logs results to a file.
- Exposes Prometheus metrics:
messages_consumed_total
kafka_message_latency_seconds
(histogram)
- Scrapes and stores time-series metrics.
- Accessed via
http://localhost:9090
.
- Visualizes Prometheus metrics with custom dashboards.
- Accessed via
http://localhost:3000
.
- Performance and stress testing on the gRPC API.
- Located in
k6_testing/test.js
.
- Services are containerized using Docker.
docker-compose.yml
runs Kafka, PostgreSQL, Prometheus, and Grafana.Dockerfile
provided for both gRPC and REST applications.
- Docker + Docker Compose
- PostgreSQL, Kafka, Prometheus, and Grafana run in Docker Compose
- Node.js
- Go
├── calculator_grpc
│ ├── calculator.proto
│ ├── client
│ │ └── main.go
│ ├── create_outbox_table.sql
│ ├── go.mod
│ ├── go.sum
│ ├── pb
│ │ ├── calculator.pb.go
│ │ └── calculator_grpc.pb.go
│ ├── poller
│ │ └── poller.go
│ └── server.go
├── calculator_rest
│ ├── calculations.log
│ ├── index.js
│ ├── package-lock.json
│ └── package.json
├── docker-compose.yml
├── k6_testing
│ └── test.js
├── prometheus.yml
└── readme
docker-compose up -d
Verify services:
- Kafka:
localhost:9092
- PostgreSQL:
localhost:5431
(user:postgres
, password:mysecretpassword
) - Prometheus:
http://localhost:9090
- Grafana:
http://localhost:3001
(login: admin / admin)
cd calculator_grpc
go mod tidy
Default password:
mysecretpassword
(used inserver.go
)
go run server.go
In a separate terminal:
go run poller/poller.go
cd calculator_rest
npm install
node index.js
- Exposes
GET /last-record
- Exposes Prometheus metrics at:
http://localhost:3000/metrics
You can use a gRPC client, or run the CLI client in calculator_grpc/client/main.go
.
Example:
grpcurl -plaintext -d '{"num1": 3, "num2": 4}' localhost:50051 CalculatorService/Add
🔍 Prometheus (http://localhost:9090)
Try queries like:
messages_consumed_total
rate(messages_consumed_total[1m])
histogram_quantile(0.95, rate(kafka_message_latency_seconds_bucket[1m]))
📊 Grafana (http://localhost:3001)
-
Add Prometheus data source (URL:
http://host.docker.internal:9090
) -
Create dashboards with:
messages_consumed_total
kafka_message_latency_seconds
To run load tests on the gRPC API:
cd k6_testing
k6 run test.js
Ensure gRPC server is running locally or exposed on the target port.
- Outbox pattern ensures reliable delivery from DB to Kafka.
- Latency is calculated using production timestamp inside Kafka message and time of consumption.
- Prometheus scrapes metrics from REST container's
/metrics
endpoint.
- Add retry mechanism and dead-letter queue
- Add persistent volume claims for stateful services
- Visualize latency per operation (add, subtract, etc.)
- full Kubernetes deployment
Abdelrahman Hedia
MIT License