
Pruthvisinh Rajput / December 14, 2025
PulseCheck is a production-ready distributed monitoring system designed to track website and API availability in real-time. Built with modern microservices architecture using Go and gRPC, it provides millisecond-precision health checks, persistent monitoring configurations, and comprehensive distributed tracing capabilities with OpenTelemetry.
APIs Repository | Checker Service | Monitor Service
PulseCheck follows a distributed microservices architecture with three main components:
βββββββββββββββββββ
β Client App β
ββββββββββ¬βββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β Monitor Service :50051 β β Checker Service :50052 β
ββββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββ€
β β’ Monitor gRPC API βββββββββββΆβ β’ Checker gRPC API β
β β’ Business Logic β β β’ Health Check Logic β
β β’ PostgreSQL DB β β β’ HTTP Client β
ββββββββββββββββββββββββββ ββββββββββββ¬ββββββββββββββββ
β β
β βΌ
β βββββββββββββββββββββββ
β β Target URLs β
β β (HTTP/HTTPS) β
β βββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β Shared APIs β β Jaeger/OTLP Collector β
β (Protocol Buffers) ββββββββββββ (Distributed Tracing) β
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
Flow:
1. Client β Monitor Service (CreateMonitor/GetMonitor)
2. Monitor Service β Checker Service (CheckURL)
3. Checker Service β Target URLs (HTTP GET)
4. All services β Jaeger (Traces)
1. pulse-check-apis - Shared API Definitions
2. checkerd - Checker Service (Port: 50052)
3. monitord - Monitor Service (Port: 50051)
To set up PulseCheck locally, follow these steps:
Prerequisites: Go 1.25+, PostgreSQL, Docker (optional)
Clone all three repositories:
mkdir pulsecheck && cd pulsecheck
git clone https://github.com/impruthvi/pulse-check-apis.git apis
git clone https://github.com/impruthvi/pulse-check-checker.git checkerd
git clone https://github.com/impruthvi/pulse-check-monitor.git monitord
Set up PostgreSQL database:
createdb pulsecheck
Configure environment variables:
cd monitord
cp .env.example .env
Edit .env with your settings:
DB_URL=postgresql://user:password@localhost:5432/pulsecheck?sslmode=disable
CHECKER_SERVICE_URL=localhost:50052
OTLP_ENDPOINT=localhost:4317
Start the services:
# Terminal 1: Checker Service
cd checkerd
go mod download
go run main.go
# Terminal 2: Monitor Service
cd monitord
go mod download
go run main.go
Optional: Run Jaeger for tracing:
docker run -d --name jaeger \
-e COLLECTOR_OTLP_ENABLED=true \
-p 16686:16686 -p 4317:4317 \
jaegertracing/all-in-one:latest
Access Jaeger UI at http://localhost:16686.
Create a new monitor:
grpcurl -plaintext \
-d '{
"url": "https://example.com",
"interval_seconds": 60
}' \
-import-path ./apis \
-proto monitor/v1/monitor.proto \
localhost:50051 \
monitor.v1.MonitorService/CreateMonitor
# Response:
# {
# "monitor": {
# "id": "550e8400-e29b-41d4-a716-446655440000",
# "url": "https://example.com",
# "intervalSeconds": 60,
# "status": "PENDING"
# }
# }
Get monitor status (performs real-time check):
grpcurl -plaintext \
-d '{
"id": "550e8400-e29b-41d4-a716-446655440000"
}' \
-import-path ./apis \
-proto monitor/v1/monitor.proto \
localhost:50051 \
monitor.v1.MonitorService/GetMonitor
# Response:
# {
# "monitor": {
# "id": "550e8400-e29b-41d4-a716-446655440000",
# "url": "https://example.com",
# "intervalSeconds": 60,
# "status": "UP",
# "lastCheckedAt": "2024-12-14T10:30:45Z",
# "responseTimeMs": "145"
# }
# }
Direct health check (Checker Service):
grpcurl -plaintext \
-d '{
"monitor_id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://google.com"
}' \
-import-path ./apis \
-proto checker/v1/checker.proto \
localhost:50052 \
checker.v1.CheckerService/CheckURL
# Response:
# {
# "monitorId": "550e8400-e29b-41d4-a716-446655440000",
# "url": "https://google.com",
# "status": "UP",
# "responseTimeMs": "87",
# "statusCode": 200,
# "checkedAt": "2024-12-14T10:31:20Z"
# }
http://localhost:16686monitord or checkerdCreate Monitor: Client calls monitord.CreateMonitor(url, interval) to
create a monitor record with "PENDING" status and returns a unique UUID.
Get Monitor Status: Client calls monitord.GetMonitor(id) which
retrieves the configuration, performs a real-time health check via
checkerd.CheckURL(), and returns the updated status.
Health Check: The checker service makes an HTTP GET request to the target URL, measures response time in milliseconds, evaluates status (200-399 = UP), and exports traces.
PulseCheck includes comprehensive distributed tracing with automatic gRPC instrumentation, service-to-service tracking, database query tracing, and custom spans for business logic. All traces include rich attributes like monitor IDs, URLs, status codes, and response times.
View traces in Jaeger UI at http://localhost:16686 to see end-to-end request
flows, performance metrics, and error tracking across all services.
Build and run with Docker:
# Build Checker Service
cd checkerd
docker build -t pulsecheck-checker .
docker run -p 50052:50052 pulsecheck-checker
# Build Monitor Service
cd monitord
docker build -t pulsecheck-monitor .
docker run -p 50051:50051 \
-e DB_URL=postgresql://user:password@host.docker.internal:5432/pulsecheck \
-e CHECKER_SERVICE_URL=host.docker.internal:50052 \
pulsecheck-monitor
For production deployment, use Docker Compose with PostgreSQL, both services, and Jaeger for a complete monitoring stack.
We welcome contributions to enhance PulseCheck. Here's how you can contribute:
git checkout -b feature-name).git commit -m "Feature description").git push origin feature-name).This project is licensed under the MIT License. Feel free to use and modify as per your needs.
PulseCheck is a production-ready monitoring solution that demonstrates modern microservices architecture principles. Built with Go and gRPC, it provides high-performance health checking capabilities with comprehensive observability through OpenTelemetry integration.
Whether you're monitoring a handful of endpoints or building a large-scale monitoring platform, PulseCheck offers a solid foundation with its clean architecture, distributed tracing, and scalable design.