# Discovery 手册
`rs-zero` 的 `discovery` feature 提供服务发现基础模型和 adapter 边界。
## 核心能力
- `ServiceInstance`:服务实例、endpoint、metadata、weight、health。
- discovery/registry trait:支持 discover、register、deregister 和 watch/refresh 语义。
- static、memory、DNS adapter。
- round-robin selector。
- etcd/Kubernetes adapter 分别通过 `discovery-etcd` 和 `discovery-kube` feature 开启;`discovery-etcd` 使用真实 etcd v3 client,`discovery-kube` 使用真实 Kubernetes EndpointSlice watcher。
## etcd registry
启用 `discovery-etcd` 后,`EtcdRegistry::connect` 会连接 etcd,并支持:
- `register`:写入 `/prefix/{service}/{id}`,value 为 `ServiceInstance` JSON。
- lease keep-alive:注册时创建 lease,后台续期,`deregister` 停止续期并 revoke lease。
- `discover`:按 service prefix 查询,只返回 healthy instance;空结果返回 `NoInstances`。
- `update_health`:更新已注册实例的 healthy 字段并保留 lease。
- `watch_service`:监听 service prefix 的 put/delete 事件;stream 失败后按 `BackoffConfig` 重连。
最小配置示例:
```rust
use rs_zero::discovery_etcd::{BackoffConfig, EtcdDiscoveryConfig, EtcdRegistry};
use std::time::Duration;
# async fn build_registry() -> Result<EtcdRegistry, Box<dyn std::error::Error>> {
let registry = EtcdRegistry::connect(EtcdDiscoveryConfig {
endpoints: vec!["http://127.0.0.1:2379".to_string()],
prefix: "/rs-zero".to_string(),
lease_ttl: 30,
reconnect_interval: Duration::from_secs(1),
connect_timeout: Duration::from_secs(3),
operation_timeout: Duration::from_secs(3),
keep_alive_interval: Duration::from_secs(5),
keep_alive_timeout: Duration::from_secs(3),
watch_backoff: BackoffConfig::default(),
auth: None,
})
.await?;
# Ok(registry)
# }
```
## Kubernetes discovery
启用 `discovery-kube` 后,`KubeDiscovery::connect` 会从 kubeconfig 或 in-cluster 环境创建 Kubernetes client,并监听指定 namespace 的 `discovery.k8s.io/v1 EndpointSlice`。
主路径支持:
- `connect` / `from_client`:启动真实 EndpointSlice watcher;`from_snapshot` 仅保留给 fixture 和离线测试。
- 初始化同步:处理 `Init` / `InitApply` / `InitDone`,首次同步完成前返回可诊断错误。
- 增删更新:处理 `Apply` / `Delete`,本地缓存按 EndpointSlice 贡献更新,删除后不会保留旧实例。
- 健康过滤:只返回 ready 且非 terminating endpoint。
- 配置:`context`、`namespace`、`service_name`、`label_selector`、`field_selector`、`port_name`、`watch_timeout`、`page_size`、`sync_timeout` 和 metadata。
最小配置示例:
```rust
use rs_zero::discovery_kube::{KubeDiscovery, KubeDiscoveryConfig};
use std::time::Duration;
# async fn build_discovery() -> Result<KubeDiscovery, Box<dyn std::error::Error>> {
let discovery = KubeDiscovery::connect(KubeDiscoveryConfig {
context: Some("docker-desktop".to_string()),
namespace: "default".to_string(),
service_name: Some("api".to_string()),
port_name: Some("http".to_string()),
sync_timeout: Duration::from_secs(10),
..KubeDiscoveryConfig::default()
})
.await?;
# Ok(discovery)
# }
```
## 使用建议
- 本地开发优先使用 static 或 memory adapter。
- 生产注册中心接入前先确认 health、metadata、权重、lease TTL、keep-alive、timeout、Kubernetes RBAC 和 watch 重连策略。
- 外部服务测试默认 ignored,不应纳入默认 CI 主路径。
## 相关示例与测试
- `examples/discovery-hello/README.md`
- `examples/production-adapters/etcd-discovery.rs`
- `cargo test --test discovery_integration`
- `cargo test --no-default-features --features discovery-etcd --test discovery_etcd_codec`
- `RS_ZERO_ETCD_ENDPOINT=http://127.0.0.1:2379 cargo test --no-default-features --features discovery-etcd --test discovery_etcd_external -- --ignored`
- `cargo test --no-default-features --features discovery-kube --test discovery_kube_mapper`
- `RS_ZERO_KUBE_EXTERNAL=1 cargo test --no-default-features --features discovery-kube --test discovery_kube_external -- --ignored`