1
//! Channel tasks of the arti-relay.
2
//!
3
//! The tasks are:
4
//!     * [`ChannelHouseKeepingTask`] which is in charge of regurlarly going over existing channels
5
//!       to clean up expiring ones and prune duplicates. At the start, it will run in
6
//!       [`ChannelHouseKeepingTask::START_TICK_TIME`] seconds and then the channel expiry function
7
//!       tells it how much time to sleep.
8

            
9
use anyhow::Context;
10
use std::{
11
    sync::{Arc, Weak},
12
    time::Duration,
13
};
14
use tracing::debug;
15

            
16
use tor_chanmgr::ChanMgr;
17
use tor_rtcompat::Runtime;
18

            
19
/// Channel housekeeping standalone background task.
20
pub(crate) struct ChannelHouseKeepingTask<R: Runtime> {
21
    /// Weak reference to the ChanMgr. If it disappears, task stops.
22
    mgr: Weak<ChanMgr<R>>,
23
}
24

            
25
impl<R: Runtime> ChannelHouseKeepingTask<R> {
26
    /// Starting tick time is to run in 3 minutes. The ChanMgr expire channels uses a default of
27
    /// 180 seconds and so we simply align with that for the first run. After that, the channel
28
    /// subsystems will tell us how long to wait if any channels.
29
    const START_TICK_TIME: Duration = Duration::from_secs(180);
30

            
31
    /// Constructor.
32
    pub(crate) fn new(mgr: &Arc<ChanMgr<R>>) -> Self {
33
        Self {
34
            mgr: Arc::downgrade(mgr),
35
        }
36
    }
37

            
38
    /// Run the background task.
39
    #[allow(clippy::unused_async)] // TODO(relay)
40
    async fn run(&mut self) -> anyhow::Result<Duration> {
41
        let mgr = Weak::upgrade(&self.mgr).context("Channel manager is gone")?;
42
        // Expire any channels that are possibly closing.
43
        let next_expiry = mgr.expire_channels();
44

            
45
        // TODO: Another action is to prune duplicate channels like C-tor does in
46
        // channel_update_bad_for_new_circs().
47
        Ok(next_expiry)
48
    }
49

            
50
    /// Start the task.
51
    pub(crate) async fn start(&mut self) -> anyhow::Result<void::Void> {
52
        let mut next_tick_in = Self::START_TICK_TIME;
53
        debug!("Channel housekeeping task starting.");
54
        loop {
55
            // Sleep until next tick.
56
            tokio::time::sleep(next_tick_in).await;
57
            // Run this task. The returned value is the next tick.
58
            next_tick_in = self
59
                .run()
60
                .await
61
                .context("Shutting down channel housekeeping task")?;
62
        }
63
    }
64
}