Skip to main content

Getting Started with Saga Service Discovery

Saga is a centralized service discovery system that enables microservices to register themselves and discover other services dynamically. Built with Rust and Actix Web, Saga provides high-performance service discovery with Redis-backed storage and comprehensive HTTP API and CLI interfaces.

What is Service Discovery?

Service discovery is a key component of microservices architectures that allows services to find and communicate with each other without hardcoded URLs. Saga provides this capability with automatic registration, health monitoring, and dynamic routing.

Prerequisites

Before you begin, ensure you have the following installed:

# Install Rust using rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Verify installation
rustc --version
cargo --version
Quick Setup

If you're using Docker Compose, Redis is already configured in infra/compose.yml. Simply run docker compose -f infra/compose.yml up -d redis to start Redis.

Quick Start

Follow these steps to get Saga running locally in under 5 minutes.

Step 1: Start Redis

Saga requires Redis as its backend storage. Choose your preferred method:

# From the project root
cd /Users/mitch/work/one
docker compose -f infra/compose.yml up -d redis

# Verify Redis is healthy
docker compose -f infra/compose.yml ps redis
Expected Output
NAME      STATUS
redis Up (healthy)
Redis Connection

If Redis is not accessible, Saga will start but service registration and discovery will fail. Always verify Redis connectivity before proceeding.

Step 2: Start Saga Service

Start Saga in development mode using one of these methods:

# From project root
REDIS_URL=redis://localhost:6379 PORT=8030 HOST=0.0.0.0 make saga-dev
Makefile Benefits

The Makefile provides a consistent interface across all services and handles environment setup automatically.

Step 3: Verify Saga is Running

Check the health endpoint to confirm Saga is operational:

curl http://localhost:8030/api/v1/health | jq .
Expected Response
{
"status": "healthy",
"service": "saga",
"version": "0.8.1",
"redis": "connected",
"cache": {
"size": 0,
"hits": 0,
"misses": 0,
"hit_ratio": 0.0,
"last_refresh": "2025-12-22T14:29:53.944455Z"
}
}
Understanding the Health Response
  • status: Overall service health (healthy or unhealthy)
  • redis: Connection status (connected or disconnected)
  • cache: In-memory cache statistics for performance monitoring
  • version: Current Saga version

If redis shows disconnected, check your Redis connection and REDIS_URL environment variable.

Testing Locally

Now that Saga is running, let's test the core functionality with practical examples.

Register a Test Service

Register a service to test the registration functionality:

curl -X POST http://localhost:8030/api/v1/services/register \
-H "Content-Type: application/json" \
-d '{
"service_name": "test-service",
"service_url": "http://localhost:8080",
"capabilities": ["rest"]
}'
Registration Response
{
"service_name": "test-service",
"service_url": "http://localhost:8080",
"service_id": "a674dbe7-5147-441b-ae56-f1c05f61cdbd",
"registered_at": "2025-12-22T14:30:38.531328+00:00",
"capabilities": ["rest"],
"ttl": 60
}

Key Fields Explained:

  • service_id: Unique UUID assigned to this registration
  • registered_at: Timestamp when the service was registered
  • ttl: Time-to-live in seconds (service expires after 60 seconds without heartbeat)
Service Capabilities

Valid capabilities include: rest, graphql, grpc, and mcp. Services can declare multiple capabilities:

{
"service_name": "api-gateway",
"service_url": "http://localhost:8000",
"capabilities": ["rest", "graphql", "grpc"]
}

List All Services

Retrieve a list of all registered services:

curl http://localhost:8030/api/v1/services | jq .
Services List Response
{
"services": [
{
"service_name": "test-service",
"service_url": "http://localhost:8080",
"service_id": "a674dbe7-5147-441b-ae56-f1c05f61cdbd",
"registered_at": "2025-12-22T14:30:38.531328+00:00",
"last_heartbeat": "2025-12-22T14:30:38.531330+00:00",
"capabilities": ["rest"]
}
],
"total": 1
}

Understanding the Response:

  • services: Array of all registered services with full metadata
  • total: Count of registered services
  • last_heartbeat: Last time the service sent a heartbeat (keeps registration alive)

Discover a Specific Service

Query details for a specific service by name:

curl http://localhost:8030/api/v1/services/test-service | jq .
Service Details Response
{
"service_name": "test-service",
"service_url": "http://localhost:8080",
"service_id": "a674dbe7-5147-441b-ae56-f1c05f61cdbd",
"registered_at": "2025-12-22T14:30:38.531328+00:00",
"last_heartbeat": "2025-12-22T14:30:38.531330+00:00",
"capabilities": ["rest"]
}
Service Expiration

Services expire after their TTL (default 60 seconds) if no heartbeat is received. Always implement heartbeat logic in your services to keep registrations alive.

Using the CLI

Saga provides a comprehensive command-line interface for managing services without making HTTP requests.

List Services

cd shared/saga
cargo run -- service list

Output:

2025-12-22T14:30:13.951320Z  INFO saga::services::registration: Listed 0 registered services
No services registered.

Register a Service

cargo run -- service register \
--name my-service \
--url http://localhost:8000 \
--capabilities rest,graphql
CLI vs API

The CLI is convenient for manual operations and scripts, while the API is better for programmatic integration in your services.

Get Service Details

cargo run -- service get my-service

Unregister a Service

cargo run -- service unregister my-service
CLI Help

Get help for any command:

cargo run -- --help
cargo run -- service --help
cargo run -- service register --help

Development Workflow

Running in Development Mode

For active development with hot reload:

# Start with watch mode
make saga-watch

Running Tests

# Using Makefile
make saga-test

# Or using cargo
cd shared/saga
cargo test

Test Coverage:

  • Unit tests for core functionality
  • Integration tests for API endpoints
  • End-to-end tests for complete workflows

Common Workflows

Complete Service Registration Flow

Here's a complete example of registering and using a service:

# 1. Register the service
curl -X POST http://localhost:8030/api/v1/services/register \
-H "Content-Type: application/json" \
-d '{
"service_name": "authentication",
"service_url": "http://localhost:8001",
"capabilities": ["rest", "graphql"]
}'

# 2. Verify registration
curl http://localhost:8030/api/v1/services/authentication

# 3. Send heartbeat to keep it alive
curl -X POST http://localhost:8030/api/v1/services/authentication/heartbeat

# 4. Discover from another service
curl http://localhost:8030/api/v1/services/authentication
Best Practices
  1. Register on startup: Register your service when it starts
  2. Implement heartbeats: Send heartbeats every 30 seconds to keep registration alive
  3. Handle failures: Implement fallback logic if Saga is unavailable
  4. Monitor health: Check Saga health endpoint regularly

Next Steps

Now that you have Saga running locally, explore these resources:

You're Ready!

Saga is now running and ready for integration. Start registering your services and discover the power of dynamic service discovery!