# revoke-registry
Service registry module for the Revoke microservices framework, providing service discovery and health monitoring capabilities.
## Features
- **Multiple Backends**: Support for Consul, etcd, and in-memory implementations
- **Service Discovery**: Automatic service registration and discovery
- **Health Monitoring**: Active and passive health checks
- **Load Balancing**: Integration with various load balancing strategies
- **Metadata Support**: Attach custom metadata to services
- **Watch Support**: Real-time updates on service changes
- **High Availability**: Support for registry clustering
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
revoke-registry = { version = "0.1", features = ["consul"] }
```
## Feature Flags
- `memory`: In-memory registry (default, useful for testing)
- `consul`: HashiCorp Consul integration
- `etcd`: etcd v3 integration
- `kubernetes`: Kubernetes service discovery
- `full`: Enable all backends
## Quick Start
```rust
use revoke_registry::{ServiceRegistry, ServiceInfo};
use revoke_core::{ServiceRegistry as RegistryTrait, Protocol};
use uuid::Uuid;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create registry client
let registry = ServiceRegistry::consul("http://localhost:8500").await?;
// Register service
let service = ServiceInfo {
id: Uuid::new_v4(),
name: "user-service".to_string(),
version: "1.0.0".to_string(),
address: "192.168.1.100".to_string(),
port: 8080,
protocol: Protocol::Http,
metadata: Default::default(),
};
registry.register(service).await?;
// Discover services
let services = registry.get_service("user-service").await?;
for svc in services {
println!("Found: {}:{}", svc.address, svc.port);
}
Ok(())
}
```
## Backend Implementations
### Memory Registry
In-memory implementation for development and testing:
```rust
use revoke_registry::memory::MemoryRegistry;
let registry = MemoryRegistry::new();
// Register with TTL
registry.register_with_ttl(service, Duration::from_secs(30)).await?;
// Get all services
let all_services = registry.list_all_services().await?;
```
### Consul Registry
HashiCorp Consul integration with full feature support:
```rust
use revoke_registry::consul::{ConsulRegistry, ConsulConfig};
use std::time::Duration;
let config = ConsulConfig {
address: "localhost:8500".to_string(),
datacenter: Some("dc1".to_string()),
token: None, // ACL token if needed
check_interval: Duration::from_secs(10),
deregister_critical: "30s".to_string(),
..Default::default()
};
let registry = ConsulRegistry::new(config).await?;
// Enable health checks
registry.enable_health_check(
service_id,
HealthCheckConfig {
interval: Duration::from_secs(10),
timeout: Duration::from_secs(5),
deregister_after: Duration::from_secs(30),
}
).await?;
```
### etcd Registry
etcd v3 API integration:
```rust
use revoke_registry::etcd::{EtcdRegistry, EtcdConfig};
let config = EtcdConfig {
endpoints: vec!["http://localhost:2379".to_string()],
username: None,
password: None,
ttl: 60, // Service TTL in seconds
..Default::default()
};
let registry = EtcdRegistry::new(config).await?;
// Watch for service changes
let mut watcher = registry.watch("user-service").await?;
while let Some(event) = watcher.next().await {
match event {
ServiceEvent::Added(service) => println!("Service added: {}", service.id),
ServiceEvent::Modified(service) => println!("Service modified: {}", service.id),
ServiceEvent::Removed(id) => println!("Service removed: {}", id),
}
}
```
## Service Discovery Patterns
### Client-Side Discovery
```rust
use revoke_registry::discovery::DiscoveryClient;
let discovery = DiscoveryClient::new(registry);
// Get service instance with load balancing
let instance = discovery
.get_instance("user-service")
.with_load_balancer(LoadBalancer::RoundRobin)
.await?;
// Make request to the instance
let url = format!("http://{}:{}/api/users", instance.address, instance.port);
```
### Server-Side Discovery
```rust
use revoke_registry::discovery::ServiceResolver;
let resolver = ServiceResolver::new(registry);
// Resolve service name to address
let endpoint = resolver.resolve("user-service").await?;
// Use with HTTP client
let client = reqwest::Client::new();
let response = client.get(&endpoint.url("/api/users")).send().await?;
```
## Health Checking
### Active Health Checks
```rust
use revoke_registry::health::{HealthChecker, HealthCheckType};
let checker = HealthChecker::new(registry);
// HTTP health check
checker.add_check(
service_id,
HealthCheckType::Http {
url: "http://localhost:8080/health".to_string(),
method: "GET".to_string(),
expected_status: 200,
timeout: Duration::from_secs(5),
}
).await?;
// TCP health check
checker.add_check(
service_id,
HealthCheckType::Tcp {
address: "localhost:8080".to_string(),
timeout: Duration::from_secs(5),
}
).await?;
// Script health check
checker.add_check(
service_id,
HealthCheckType::Script {
command: "/usr/local/bin/check-health.sh".to_string(),
args: vec![service_id.to_string()],
timeout: Duration::from_secs(10),
}
).await?;
```
### Passive Health Checks
```rust
use revoke_registry::health::PassiveHealthCheck;
let passive_check = PassiveHealthCheck::new()
.failure_threshold(5) // Mark unhealthy after 5 failures
.success_threshold(2) // Mark healthy after 2 successes
.timeout(Duration::from_secs(30));
// Report request outcome
passive_check.report_success(service_id).await;
passive_check.report_failure(service_id).await;
// Check health status
let is_healthy = passive_check.is_healthy(service_id).await;
```
## Advanced Features
### Service Metadata
```rust
let mut metadata = HashMap::new();
metadata.insert("region".to_string(), "us-west-2".to_string());
metadata.insert("zone".to_string(), "us-west-2a".to_string());
metadata.insert("version".to_string(), "1.2.3".to_string());
metadata.insert("commit".to_string(), "abc123".to_string());
let service = ServiceInfo {
metadata,
..Default::default()
};
// Query by metadata
let services = registry
.query_services()
.with_metadata("region", "us-west-2")
.with_metadata("version", "1.2.3")
.execute()
.await?;
```
### Service Groups
```rust
use revoke_registry::groups::ServiceGroup;
// Create service group
let group = ServiceGroup::new("api-services")
.add_service("user-service")
.add_service("order-service")
.add_service("payment-service");
registry.register_group(group).await?;
// Get all services in group
let services = registry.get_group("api-services").await?;
```
### Circuit Breaker Integration
```rust
use revoke_registry::resilience::RegistryCircuitBreaker;
let breaker = RegistryCircuitBreaker::new(registry)
.failure_threshold(5)
.recovery_timeout(Duration::from_secs(60));
// Discover with circuit breaker
match breaker.get_service("user-service").await {
Ok(services) => {
// Use services
}
Err(e) if e.is_circuit_open() => {
// Use fallback
}
Err(e) => {
// Handle other errors
}
}
```
### Multi-Region Support
```rust
use revoke_registry::multiregion::{MultiRegionRegistry, RegionConfig};
let regions = vec![
RegionConfig {
name: "us-west-2".to_string(),
endpoint: "http://consul-us-west-2:8500".to_string(),
priority: 1,
},
RegionConfig {
name: "us-east-1".to_string(),
endpoint: "http://consul-us-east-1:8500".to_string(),
priority: 2,
},
];
let registry = MultiRegionRegistry::new(regions).await?;
// Prefer local region
let services = registry
.get_service("user-service")
.prefer_region("us-west-2")
.await?;
```
## Performance Optimization
### Caching
```rust
use revoke_registry::cache::{CachedRegistry, CacheConfig};
let cache_config = CacheConfig {
ttl: Duration::from_secs(5),
max_size: 1000,
refresh_interval: Duration::from_secs(30),
};
let cached_registry = CachedRegistry::new(registry, cache_config);
// Cached lookups
let services = cached_registry.get_service("user-service").await?;
```
### Batch Operations
```rust
// Register multiple services
let services = vec![service1, service2, service3];
registry.register_batch(services).await?;
// Deregister multiple services
let ids = vec![id1, id2, id3];
registry.deregister_batch(ids).await?;
// Batch health updates
let updates = vec![
(id1, HealthStatus::Healthy),
(id2, HealthStatus::Unhealthy),
];
registry.update_health_batch(updates).await?;
```
## Monitoring and Metrics
```rust
use revoke_registry::metrics::RegistryMetrics;
let metrics = RegistryMetrics::new(®istry);
// Get registry statistics
let stats = metrics.get_stats().await?;
println!("Total services: {}", stats.total_services);
println!("Healthy services: {}", stats.healthy_services);
println!("Unhealthy services: {}", stats.unhealthy_services);
// Export Prometheus metrics
let prometheus_metrics = metrics.export_prometheus();
```
## Best Practices
1. **Service Naming**: Use consistent naming conventions (e.g., `service-name-v1`)
2. **Health Checks**: Always configure appropriate health checks
3. **Metadata**: Include version, region, and deployment information
4. **TTL**: Set reasonable TTL values for service registration
5. **Graceful Shutdown**: Always deregister services on shutdown
6. **Connection Pooling**: Reuse registry clients across your application
7. **Error Handling**: Implement retry logic for transient failures
## Examples
See the [examples](examples/) directory:
- `basic_registration.rs` - Simple service registration
- `health_checks.rs` - Health check configuration
- `service_discovery.rs` - Client-side discovery patterns
- `multi_region.rs` - Multi-region deployment