1
- use arc_swap:: ArcSwap ;
1
+ use arc_swap:: { ArcSwap , Guard } ;
2
2
use std:: collections:: HashSet ;
3
3
use std:: fs;
4
4
use std:: ops:: RangeInclusive ;
5
5
use std:: path:: Path ;
6
6
use std:: sync:: Arc ;
7
7
use std:: time:: Instant ;
8
8
9
- use anyhow:: Context ;
10
9
use chrono:: { Duration , Utc } ;
10
+ use log:: error;
11
11
use serde:: { Deserialize , Serialize } ;
12
12
13
13
use crate :: db;
@@ -109,13 +109,21 @@ pub struct MasterCommitCache {
109
109
110
110
impl MasterCommitCache {
111
111
/// Download the master-branch Rust commit list
112
- async fn download ( ) -> anyhow:: Result < Self > {
112
+ pub async fn download ( ) -> anyhow:: Result < Self > {
113
113
let commits = collector:: master_commits ( ) . await ?;
114
114
Ok ( Self {
115
115
commits,
116
116
updated : Instant :: now ( ) ,
117
117
} )
118
118
}
119
+
120
+ /// Returns an empty cache that is marked as stale
121
+ pub fn empty ( ) -> Self {
122
+ Self {
123
+ commits : Vec :: new ( ) ,
124
+ updated : Instant :: now ( ) - std:: time:: Duration :: from_secs ( 2 * 60 ) ,
125
+ }
126
+ }
119
127
}
120
128
121
129
/// Site context object that contains global data
@@ -127,7 +135,7 @@ pub struct SiteCtxt {
127
135
/// Index of various common queries
128
136
pub index : ArcSwap < crate :: db:: Index > ,
129
137
/// Cached master-branch Rust commits
130
- pub master_commits : ArcSwap < MasterCommitCache > ,
138
+ pub master_commits : Arc < ArcSwap < MasterCommitCache > > , // outer Arc enables mutation in background task
131
139
/// Database connection pool
132
140
pub pool : Pool ,
133
141
}
@@ -180,12 +188,14 @@ impl SiteCtxt {
180
188
}
181
189
} ;
182
190
183
- let master_commits = MasterCommitCache :: download ( ) . await ?;
191
+ let master_commits = MasterCommitCache :: download ( )
192
+ . await
193
+ . unwrap_or ( MasterCommitCache :: empty ( ) ) ; // still run the site if we can't get the commits right now
184
194
185
195
Ok ( Self {
186
196
config,
187
197
index : ArcSwap :: new ( Arc :: new ( index) ) ,
188
- master_commits : ArcSwap :: new ( Arc :: new ( master_commits) ) ,
198
+ master_commits : Arc :: new ( ArcSwap :: new ( Arc :: new ( master_commits) ) ) ,
189
199
pool,
190
200
landing_page : ArcSwap :: new ( Arc :: new ( None ) ) ,
191
201
} )
@@ -223,14 +233,27 @@ impl SiteCtxt {
223
233
)
224
234
}
225
235
226
- /// Download master-branch Rust commits if the cached value is older than one minute
227
- pub async fn update_master_commits ( & self ) -> anyhow:: Result < ( ) > {
236
+ /// Get cached master-branch Rust commits.
237
+ /// Returns cached results immediately, but if the cached value is older than one minute,
238
+ /// updates in a background task for next time.
239
+ pub fn get_master_commits ( & self ) -> Guard < Arc < MasterCommitCache > > {
228
240
let commits = self . master_commits . load ( ) ;
241
+
229
242
if commits. updated . elapsed ( ) > std:: time:: Duration :: from_secs ( 60 ) {
230
- self . master_commits
231
- . store ( Arc :: new ( MasterCommitCache :: download ( ) . await ?) )
243
+ let master_commits = self . master_commits . clone ( ) ;
244
+ tokio:: task:: spawn ( async move {
245
+ // if another update happens before this one is done, we will download the data twice, but that's it
246
+ match MasterCommitCache :: download ( ) . await {
247
+ Ok ( commits) => master_commits. store ( Arc :: new ( commits) ) ,
248
+ Err ( e) => {
249
+ // couldn't get the data, keep serving cached results for now
250
+ error ! ( "error retrieving master commit list: {}" , e)
251
+ }
252
+ }
253
+ } ) ;
232
254
}
233
- Ok ( ( ) )
255
+
256
+ commits
234
257
}
235
258
}
236
259
0 commit comments