refactor(grpc): bind TCP listener before etcd registration to prevent connection issues

- Change tokio-stream dependency to include net feature for TcpListenerStream
- Move TCP listener binding before etcd registry initialization in main function
- Pass pre-bound TcpListener to gRPC server instead of just SocketAddr
- Update gRPC server to use serve_with_incoming with TcpListenerStream
- Prevent peers from attempting connections before gRPC server is ready
- Ensure proper error handling for TCP binding failures during startup
This commit is contained in:
zhenyi
2026-06-11 23:07:36 +08:00
parent b797e360c0
commit 5f4e9bdfa7
3 changed files with 15 additions and 7 deletions
+12 -5
View File
@@ -37,6 +37,17 @@ async fn main() -> AppResult<()> {
let cache = Arc::new(AppCache::from_config(&config).await?);
let storage = AppS3Storage::from_config(&config).await?;
let rpc_host = config.get_env_or::<String>("APP_RPC_SELF_HOST", "0.0.0.0".to_string())?;
let rpc_port = config.get_env_or::<u16>("APP_RPC_SELF_PORT", 50050)?;
let rpc_addr: std::net::SocketAddr = format!("{rpc_host}:{rpc_port}").parse()
.map_err(|e| appks::error::AppError::Config(format!("invalid gRPC address: {e}")))?;
// Bind the TCP listener FIRST so the port is reserved before etcd registration.
// This prevents peers from trying to connect before the gRPC server is ready.
let rpc_listener = tokio::net::TcpListener::bind(rpc_addr)
.await
.map_err(|e| appks::error::AppError::Config(format!("gRPC bind failed on {rpc_addr}: {e}")))?;
let registry = Arc::new(EtcdRegistry::connect(&config).await?);
registry.start_discovery().await?;
registry
@@ -57,13 +68,9 @@ async fn main() -> AppResult<()> {
)
.await;
let rpc_host = config.get_env_or::<String>("APP_RPC_SELF_HOST", "0.0.0.0".to_string())?;
let rpc_port = config.get_env_or::<u16>("APP_RPC_SELF_PORT", 50050)?;
let rpc_addr: std::net::SocketAddr = format!("{rpc_host}:{rpc_port}").parse()
.map_err(|e| appks::error::AppError::Config(format!("invalid gRPC address: {e}")))?;
let grpc_service = service.clone();
tokio::spawn(async move {
if let Err(e) = appks::grpc::start_grpc_server(rpc_addr, grpc_service).await {
if let Err(e) = appks::grpc::start_grpc_server(rpc_addr, rpc_listener, grpc_service).await {
tracing::error!(error = %e, "gRPC server failed");
}
});