feat(config): integrate etcd for service discovery and config management
- Add etcd-client dependency for distributed configuration storage - Implement EtcdConfig with priority: etcd > environment variables > defaults - Add ServiceRegistry for service registration with lease keep-alive - Integrate etcd-based service discovery for appks gRPC connections - Add service watcher for real-time service instance updates - Migrate Redis configuration from single URL to cluster node list - Update Dockerfile with default IMKS_HOST and IMKS_PORT environment variables - Add etcd bootstrap configuration through environment variables - Implement Redis cluster URL building with optional authentication
This commit is contained in:
@@ -2,6 +2,7 @@ use std::sync::{Arc, OnceLock};
|
||||
|
||||
use imks::database::{Database, DatabaseConfig};
|
||||
use imks::engine::server::EngineConfig;
|
||||
use imks::etcd::{EtcdConfig, ServiceRegistry};
|
||||
use imks::repo::MessageRepo;
|
||||
use imks::rpc::{AppksClients, RpcConfig};
|
||||
use imks::socket::adapter::{LocalBroadcastFn, NatsAdapter, RedisAdapter};
|
||||
@@ -17,6 +18,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
telemetry::health::init_counters();
|
||||
|
||||
let deploy = DeployConfig::from_env();
|
||||
|
||||
// Read etcd bootstrap config from env (these MUST come from env, not etcd)
|
||||
let etcd_endpoints: Vec<String> = std::env::var("ETCD_ENDPOINTS")
|
||||
.unwrap_or_else(|_| "http://localhost:2379".to_string())
|
||||
.split(',')
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
let etcd_prefix = std::env::var("ETCD_KEY_PREFIX")
|
||||
.unwrap_or_else(|_| "/appks/".to_string());
|
||||
|
||||
tracing::info!(
|
||||
adapter = %deploy.adapter_mode,
|
||||
server_id = %deploy.server_id,
|
||||
@@ -24,11 +36,33 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
"Starting imks server"
|
||||
);
|
||||
|
||||
let addr = "0.0.0.0:3000";
|
||||
let addr = "0.0.0.0:50048";
|
||||
|
||||
let rt = tokio::runtime::Runtime::new()?;
|
||||
|
||||
rt.block_on(async {
|
||||
// --- etcd: connect, register, discover appks ---
|
||||
let etcd = EtcdConfig::connect(etcd_endpoints, &etcd_prefix).await
|
||||
.unwrap_or_else(|e| {
|
||||
tracing::error!(error = %e, "etcd required but unavailable");
|
||||
panic!("etcd required: {e}")
|
||||
});
|
||||
|
||||
// Register this service so others can discover us
|
||||
let registry = ServiceRegistry::new(etcd.client(), &etcd_prefix);
|
||||
let imks_addr = etcd.get("IMKS_ADDR", "0.0.0.0:3000").await;
|
||||
registry.register("imks", &imks_addr).await.ok();
|
||||
|
||||
// Discover appks from etcd (priority > env)
|
||||
let appks_addr = etcd.discover_service("appks").await
|
||||
.ok()
|
||||
.and_then(|addrs| addrs.into_iter().next())
|
||||
.unwrap_or_else(|| {
|
||||
std::env::var("APPKS_GRPC_ADDR").unwrap_or_else(|_| "http://localhost:50051".to_string())
|
||||
});
|
||||
tracing::info!(appks_addr = %appks_addr, "appks discovered via etcd");
|
||||
etcd.start_service_watcher("appks");
|
||||
|
||||
let engine_config = EngineConfig::default();
|
||||
let mut builder = SocketServerBuilder::new(engine_config);
|
||||
let namespace_holder: Arc<OnceLock<Arc<imks::socket::namespace::NamespaceManager>>> =
|
||||
@@ -37,10 +71,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Pre-configure adapter for Redis/NATS mode.
|
||||
match deploy.adapter_mode.as_str() {
|
||||
"redis" => {
|
||||
let cluster_url = deploy.redis_cluster_url();
|
||||
let message_bus = Arc::new(
|
||||
RedisMessageBus::new(&deploy.redis_url)
|
||||
RedisMessageBus::new(&cluster_url)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to connect to Redis: {e}"))?,
|
||||
.map_err(|e| format!("Failed to connect to Redis cluster: {e}"))?,
|
||||
);
|
||||
let redis_client = message_bus.client().clone();
|
||||
let server_id = deploy.server_id.clone();
|
||||
@@ -88,7 +123,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// Initialize database + gRPC + service
|
||||
let service: Option<Arc<MessageService>> = {
|
||||
let rpc_config = RpcConfig::from_env();
|
||||
let rpc_config = RpcConfig {
|
||||
appks_addr: appks_addr.clone(),
|
||||
..RpcConfig::from_env()
|
||||
};
|
||||
let db_config = DatabaseConfig::from_env();
|
||||
|
||||
match AppksClients::connect(&rpc_config).await {
|
||||
|
||||
Reference in New Issue
Block a user