···38const MIN_NOT_FOUND_TTL: Duration = Duration::from_secs(60);
3940#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
41-enum IdentityKey {
42 Handle(Handle),
43 Did(Did),
44}
···186 /// multi-producer *single consumer* queue
187 refresh_queue: Arc<Mutex<RefreshQueue>>,
188 /// just a lock to ensure only one refresher (queue consumer) is running (to be improved with a better refresher)
189- refresher: Arc<Mutex<()>>,
190}
191192impl Identity {
···225 did_resolver: Arc::new(did_resolver),
226 cache,
227 refresh_queue: Default::default(),
228- refresher: Default::default(),
229 })
230 }
231···293 }
294 IdentityData::NotFound => {
295 if (now - *last_fetch) >= MIN_NOT_FOUND_TTL {
0296 self.queue_refresh(key).await;
297 }
298 Ok(None)
299 }
300 IdentityData::Did(did) => {
301 if (now - *last_fetch) >= MIN_TTL {
0302 self.queue_refresh(key).await;
303 }
304 Ok(Some(did.clone()))
···347 }
348 IdentityData::NotFound => {
349 if (now - *last_fetch) >= MIN_NOT_FOUND_TTL {
0350 self.queue_refresh(key).await;
351 }
352 Ok(None)
353 }
354 IdentityData::Doc(mini_did) => {
355 if (now - *last_fetch) >= MIN_TTL {
0356 self.queue_refresh(key).await;
357 }
358 Ok(Some(mini_did.clone()))
···363 /// put a refresh task on the queue
364 ///
365 /// this can be safely called from multiple concurrent tasks
366- async fn queue_refresh(&self, key: IdentityKey) {
367 // todo: max queue size
368 let mut q = self.refresh_queue.lock().await;
369 if !q.items.contains(&key) {
···440 /// run the refresh queue consumer
441 pub async fn run_refresher(&self, shutdown: CancellationToken) -> Result<(), IdentityError> {
442 let _guard = self
443- .refresher
444 .try_lock()
445 .expect("there to only be one refresher running");
446 loop {
···462 log::trace!("refreshing handle {handle:?}");
463 match self.handle_resolver.resolve(handle).await {
464 Ok(did) => {
00465 self.cache.insert(
466 task_key.clone(),
467 IdentityVal(UtcDateTime::now(), IdentityData::Did(did)),
468 );
469 }
470 Err(atrium_identity::Error::NotFound) => {
0471 self.cache.insert(
472 task_key.clone(),
473 IdentityVal(UtcDateTime::now(), IdentityData::NotFound),
474 );
475 }
476 Err(err) => {
0477 log::warn!(
478 "failed to refresh handle: {err:?}. leaving stale (should we eventually do something?)"
479 );
···488 Ok(did_doc) => {
489 // TODO: fix in atrium: should verify id is did
490 if did_doc.id != did.to_string() {
0491 log::warn!(
492 "refreshed did doc failed: wrong did doc id. dropping refresh."
493 );
···496 let mini_doc = match did_doc.try_into() {
497 Ok(md) => md,
498 Err(e) => {
0499 log::warn!(
500 "converting mini doc failed: {e:?}. dropping refresh."
501 );
502 continue;
503 }
504 };
00505 self.cache.insert(
506 task_key.clone(),
507 IdentityVal(UtcDateTime::now(), IdentityData::Doc(mini_doc)),
508 );
509 }
510 Err(atrium_identity::Error::NotFound) => {
0511 self.cache.insert(
512 task_key.clone(),
513 IdentityVal(UtcDateTime::now(), IdentityData::NotFound),
514 );
515 }
516 Err(err) => {
0517 log::warn!(
518 "failed to refresh did doc: {err:?}. leaving stale (should we eventually do something?)"
519 );
···38const MIN_NOT_FOUND_TTL: Duration = Duration::from_secs(60);
3940#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
41+pub enum IdentityKey {
42 Handle(Handle),
43 Did(Did),
44}
···186 /// multi-producer *single consumer* queue
187 refresh_queue: Arc<Mutex<RefreshQueue>>,
188 /// just a lock to ensure only one refresher (queue consumer) is running (to be improved with a better refresher)
189+ refresher_task: Arc<Mutex<()>>,
190}
191192impl Identity {
···225 did_resolver: Arc::new(did_resolver),
226 cache,
227 refresh_queue: Default::default(),
228+ refresher_task: Default::default(),
229 })
230 }
231···293 }
294 IdentityData::NotFound => {
295 if (now - *last_fetch) >= MIN_NOT_FOUND_TTL {
296+ metrics::counter!("identity_handle_refresh_queued", "reason" => "ttl", "found" => "false").increment(1);
297 self.queue_refresh(key).await;
298 }
299 Ok(None)
300 }
301 IdentityData::Did(did) => {
302 if (now - *last_fetch) >= MIN_TTL {
303+ metrics::counter!("identity_handle_refresh_queued", "reason" => "ttl", "found" => "true").increment(1);
304 self.queue_refresh(key).await;
305 }
306 Ok(Some(did.clone()))
···349 }
350 IdentityData::NotFound => {
351 if (now - *last_fetch) >= MIN_NOT_FOUND_TTL {
352+ metrics::counter!("identity_did_refresh_queued", "reason" => "ttl", "found" => "false").increment(1);
353 self.queue_refresh(key).await;
354 }
355 Ok(None)
356 }
357 IdentityData::Doc(mini_did) => {
358 if (now - *last_fetch) >= MIN_TTL {
359+ metrics::counter!("identity_did_refresh_queued", "reason" => "ttl", "found" => "true").increment(1);
360 self.queue_refresh(key).await;
361 }
362 Ok(Some(mini_did.clone()))
···367 /// put a refresh task on the queue
368 ///
369 /// this can be safely called from multiple concurrent tasks
370+ pub async fn queue_refresh(&self, key: IdentityKey) {
371 // todo: max queue size
372 let mut q = self.refresh_queue.lock().await;
373 if !q.items.contains(&key) {
···444 /// run the refresh queue consumer
445 pub async fn run_refresher(&self, shutdown: CancellationToken) -> Result<(), IdentityError> {
446 let _guard = self
447+ .refresher_task
448 .try_lock()
449 .expect("there to only be one refresher running");
450 loop {
···466 log::trace!("refreshing handle {handle:?}");
467 match self.handle_resolver.resolve(handle).await {
468 Ok(did) => {
469+ metrics::counter!("identity_handle_refresh", "success" => "true")
470+ .increment(1);
471 self.cache.insert(
472 task_key.clone(),
473 IdentityVal(UtcDateTime::now(), IdentityData::Did(did)),
474 );
475 }
476 Err(atrium_identity::Error::NotFound) => {
477+ metrics::counter!("identity_handle_refresh", "success" => "false", "reason" => "not found").increment(1);
478 self.cache.insert(
479 task_key.clone(),
480 IdentityVal(UtcDateTime::now(), IdentityData::NotFound),
481 );
482 }
483 Err(err) => {
484+ metrics::counter!("identity_handle_refresh", "success" => "false", "reason" => "other").increment(1);
485 log::warn!(
486 "failed to refresh handle: {err:?}. leaving stale (should we eventually do something?)"
487 );
···496 Ok(did_doc) => {
497 // TODO: fix in atrium: should verify id is did
498 if did_doc.id != did.to_string() {
499+ metrics::counter!("identity_did_refresh", "success" => "false", "reason" => "wrong did").increment(1);
500 log::warn!(
501 "refreshed did doc failed: wrong did doc id. dropping refresh."
502 );
···505 let mini_doc = match did_doc.try_into() {
506 Ok(md) => md,
507 Err(e) => {
508+ metrics::counter!("identity_did_refresh", "success" => "false", "reason" => "bad doc").increment(1);
509 log::warn!(
510 "converting mini doc failed: {e:?}. dropping refresh."
511 );
512 continue;
513 }
514 };
515+ metrics::counter!("identity_did_refresh", "success" => "true")
516+ .increment(1);
517 self.cache.insert(
518 task_key.clone(),
519 IdentityVal(UtcDateTime::now(), IdentityData::Doc(mini_doc)),
520 );
521 }
522 Err(atrium_identity::Error::NotFound) => {
523+ metrics::counter!("identity_did_refresh", "success" => "false", "reason" => "not found").increment(1);
524 self.cache.insert(
525 task_key.clone(),
526 IdentityVal(UtcDateTime::now(), IdentityData::NotFound),
527 );
528 }
529 Err(err) => {
530+ metrics::counter!("identity_did_refresh", "success" => "false", "reason" => "other").increment(1);
531 log::warn!(
532 "failed to refresh did doc: {err:?}. leaving stale (should we eventually do something?)"
533 );
+1-1
slingshot/src/lib.rs
···9pub use consumer::consume;
10pub use firehose_cache::firehose_cache;
11pub use healthcheck::healthcheck;
12-pub use identity::Identity;
13pub use record::{CachedRecord, ErrorResponseObject, Repo};
14pub use server::serve;
···9pub use consumer::consume;
10pub use firehose_cache::firehose_cache;
11pub use healthcheck::healthcheck;
12+pub use identity::{Identity, IdentityKey};
13pub use record::{CachedRecord, ErrorResponseObject, Repo};
14pub use server::serve;