lockbook_server_lib/
garbage_worker.rs1use std::time::Duration;
2use tracing::{debug, error, info};
3
4use lb_rs::model::clock::get_time;
5
6use crate::{
7 ServerState,
8 billing::{
9 app_store_client::AppStoreClient, google_play_client::GooglePlayClient,
10 stripe_client::StripeClient,
11 },
12 document_service::DocumentService,
13};
14
15impl<S, A, G, D> ServerState<S, A, G, D>
16where
17 S: StripeClient,
18 A: AppStoreClient,
19 G: GooglePlayClient,
20 D: DocumentService,
21{
22 pub fn start_garbage_worker(&self) {
23 let bg_self = self.clone();
24
25 tokio::spawn(async move {
26 loop {
27 tokio::time::sleep(Duration::from_secs(60)).await;
28 info!("garbage collecting");
29 bg_self.garbage_collect().await;
30 info!("garbage collected");
31 }
32 });
33 }
34
35 pub async fn garbage_collect(&self) {
36 let mut db = self.index_db.lock().await;
37 let files = db.scheduled_file_cleanups.get();
38 let mut cleaned = 0;
39 let mut skipped = 0;
40 let mut remove = vec![];
41 for ((id, hmac), time) in files {
42 if get_time().0 - time > 1000 * 60 * 5 {
43 cleaned += 1;
44 if let Err(e) = self.document_service.delete::<()>(id, hmac).await {
45 error!(
46 "failed to garbage collect {:?} {e:?}",
47 self.document_service.get_path(id, hmac)
48 );
49 } else {
50 remove.push((*id, *hmac));
51 }
52 debug!("garbage collected: {:?}", self.document_service.get_path(id, hmac));
53 } else {
54 skipped += 1;
55 }
56 }
57
58 for (id, hmac) in remove {
59 db.scheduled_file_cleanups.remove(&(id, hmac)).unwrap();
60 }
61
62 info!("cleaned {cleaned}, skipped {skipped}");
63 }
64}