dynamo_runtime/discovery.rs
1// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{Result, transports::etcd};
5
6pub use etcd::Lease;
7
8pub struct DiscoveryClient {
9 namespace: String,
10 etcd_client: etcd::Client,
11}
12
13impl DiscoveryClient {
14 /// Create a new [`DiscoveryClient`]
15 ///
16 /// This will establish a connection to the etcd server, create a primary lease,
17 /// and spawn a task to keep the lease alive and tie the lifetime of the [`Runtime`]
18 /// to the lease.
19 ///
20 /// If the lease expires, the [`Runtime`] will be shutdown.
21 /// If the [`Runtime`] is shutdown, the lease will be revoked.
22 pub(crate) fn new(namespace: String, etcd_client: etcd::Client) -> Self {
23 DiscoveryClient {
24 namespace,
25 etcd_client,
26 }
27 }
28
29 /// Get the primary lease ID
30 pub fn primary_lease_id(&self) -> i64 {
31 self.etcd_client.lease_id()
32 }
33
34 /// Create a [`Lease`] with a given time-to-live (TTL).
35 /// This [`Lease`] will be tied to the [`crate::Runtime`], but has its own independent [`crate::CancellationToken`].
36 pub async fn create_lease(&self, ttl: i64) -> Result<Lease> {
37 self.etcd_client.create_lease(ttl).await
38 }
39
40 // the following two commented out codes are not implemented, but are placeholders for proposed ectd usage patterns
41
42 // /// Create an ephemeral key/value pair tied to a lease_id.
43 // /// This is an atomic create. If the key already exists, this will fail.
44 // /// The [`etcd_client::KeyValue`] will be removed when the lease expires or is revoked.
45 // pub async fn create_ephemerial_key(&self, key: &str, value: &str, lease_id: i64) -> Result<()> {
46 // // self.etcd_client.create_ephemeral_key(key, value, lease_id).await
47 // unimplemented!()
48 // }
49
50 // /// Create a shared [`etcd_client::KeyValue`] which behaves similar to a C++ `std::shared_ptr` or a
51 // /// Rust [std::sync::Arc]. Instead of having one owner of the lease, multiple owners participate in
52 // /// maintaining the lease. In this manner, when the last member of the group sharing the lease is gone,
53 // /// the lease will be expired.
54 // ///
55 // /// Implementation notes: At the time of writing, it is unclear if we have atomics that control leases,
56 // /// so in our initial implementation, the last member of the group will not revoke the lease, so the object
57 // /// will live for upto the TTL after the last member is gone.
58 // ///
59 // /// Notes
60 // /// -----
61 // ///
62 // /// - Multiple members sharing the lease and contributing to the heartbeat might cause some overheads.
63 // /// The implementation will try to randomize the heartbeat intervals to avoid thundering herd problem,
64 // /// and with any luck, the heartbeat watchers will be able to detect when if a external member triggered
65 // /// the heartbeat checking this interval and skip unnecessary heartbeat messages.
66 // ///
67 // /// A new lease will be created for this object. If you wish to add an object to a shared group s
68 // ///
69 // /// The [`etcd_client::KeyValue`] will be removed when the lease expires or is revoked.
70 // pub async fn create_shared_key(&self, key: &str, value: &str, lease_id: i64) -> Result<()> {
71 // // self.etcd_client.create_ephemeral_key(key, value, lease_id).await
72 // unimplemented!()
73 // }
74}