dynamodb_lease/
builder.rs

1use crate::Client;
2use std::time::Duration;
3
4/// [`Client`] builder.
5pub struct ClientBuilder {
6    table_name: String,
7    lease_ttl_seconds: u32,
8    extend_period: Option<Duration>,
9    acquire_cooldown: Duration,
10}
11
12impl Default for ClientBuilder {
13    fn default() -> Self {
14        Self {
15            table_name: "leases".into(),
16            lease_ttl_seconds: 60,
17            extend_period: None,
18            acquire_cooldown: Duration::from_secs(1),
19        }
20    }
21}
22
23impl ClientBuilder {
24    /// Sets the lease table name where the lease info will be stored.
25    /// The table must have the correct schema.
26    ///
27    /// Default `"leases"`.
28    pub fn table_name(mut self, table_name: impl Into<String>) -> Self {
29        self.table_name = table_name.into();
30        self
31    }
32
33    /// Sets the time to live for each lease (or lease extension) in seconds.
34    /// **Must be at least 2**.
35    ///
36    /// Note: Time to live is implemented using the native dynamodb feature. As this
37    /// is based on unix timestamps the unit is seconds. This makes extending ttls lower
38    /// than 2s not reliable.
39    ///
40    /// Note: A [`crate::Lease`] will attempt to extend itself in the background until dropped
41    /// and then release itself. However, since db comms failing after acquiring a lease
42    /// is possible, this ttl is the _guaranteed_ lifetime of a lease. As such, and since
43    /// ttl is not in normal operation relied upon to release leases, it may make sense
44    /// to set this higher than the max operation time the lease is wrapping.
45    ///
46    /// So, for example, if the locked task can take 1s to 5m a ttl of 10m should provide
47    /// a decent guarantee that such tasks will never execute concurrently. In normal operation
48    /// each lease will release (be deleted) immediately after dropping, so having a high
49    /// ttl only affects the edge case where the extend/drop db interactions fail.
50    ///
51    /// Default `60`.
52    ///
53    /// # Panics
54    /// Panics if less than 2s.
55    pub fn lease_ttl_seconds(mut self, seconds: u32) -> Self {
56        assert!(
57            seconds >= 2,
58            "must be at least 2s, shorter ttls are not supported"
59        );
60        self.lease_ttl_seconds = seconds;
61        self
62    }
63
64    /// Sets the periodic duration between each background attempt to extend the lease. These
65    /// happen continually while the [`crate::Lease`] is alive.
66    ///
67    /// Each extension renews the lease to the full ttl. This duration must be less
68    /// than the ttl.
69    ///
70    /// Default `lease_ttl_seconds / 2`.
71    ///
72    /// # Panics
73    /// Panics if zero.
74    pub fn extend_every(mut self, extend_period: Duration) -> Self {
75        assert!(extend_period > Duration::ZERO, "must be greater than zero");
76        self.extend_period = Some(extend_period);
77        self
78    }
79
80    /// Sets how long [`Client::acquire`] waits between attempts to acquire a lease.
81    ///
82    /// Default `1s`.
83    pub fn acquire_cooldown(mut self, cooldown: Duration) -> Self {
84        self.acquire_cooldown = cooldown;
85        self
86    }
87
88    /// Builds a [`Client`] and checks the dynamodb table is active with the correct schema.
89    ///
90    /// # Panics
91    /// Panics if `extend_period` is not less than `lease_ttl_seconds`.
92    pub async fn build_and_check_db(
93        self,
94        dynamodb_client: aws_sdk_dynamodb::Client,
95    ) -> anyhow::Result<Client> {
96        let extend_period = self
97            .extend_period
98            .unwrap_or_else(|| Duration::from_secs_f64(self.lease_ttl_seconds as f64 / 2.0));
99        assert!(
100            extend_period < Duration::from_secs(self.lease_ttl_seconds as _),
101            "renew_period must be less than ttl"
102        );
103
104        let client = Client {
105            table_name: self.table_name.into(),
106            client: dynamodb_client,
107            lease_ttl_seconds: self.lease_ttl_seconds,
108            extend_period,
109            acquire_cooldown: self.acquire_cooldown,
110            local_locks: <_>::default(),
111        };
112
113        client.check_schema().await?;
114
115        Ok(client)
116    }
117}