use weak references to break services dependency cycle

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-07-28 07:22:51 +00:00 committed by Jason Volk
parent a74613be96
commit e37ac56dba

View file

@ -3,7 +3,7 @@ use std::{
collections::BTreeMap, collections::BTreeMap,
fmt::Write, fmt::Write,
ops::Deref, ops::Deref,
sync::{Arc, OnceLock, RwLock}, sync::{Arc, OnceLock, RwLock, Weak},
}; };
use async_trait::async_trait; use async_trait::async_trait;
@ -53,7 +53,7 @@ pub(crate) struct Args<'a> {
/// Circular-dependencies between services require this indirection. /// Circular-dependencies between services require this indirection.
pub(crate) struct Dep<T> { pub(crate) struct Dep<T> {
dep: OnceLock<Arc<T>>, dep: OnceLock<Arc<T>>,
service: Arc<Map>, service: Weak<Map>,
name: &'static str, name: &'static str,
} }
@ -65,8 +65,14 @@ impl<T: Send + Sync + 'static> Deref for Dep<T> {
/// Dereference a dependency. The dependency must be ready or panics. /// Dereference a dependency. The dependency must be ready or panics.
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.dep self.dep.get_or_init(|| {
.get_or_init(|| require::<T>(&self.service, self.name)) let service = self
.service
.upgrade()
.expect("services map exists for dependency initialization.");
require::<T>(&service, self.name)
})
} }
} }
@ -75,7 +81,7 @@ impl Args<'_> {
pub(crate) fn depend<T: Send + Sync + 'static>(&self, name: &'static str) -> Dep<T> { pub(crate) fn depend<T: Send + Sync + 'static>(&self, name: &'static str) -> Dep<T> {
Dep::<T> { Dep::<T> {
dep: OnceLock::new(), dep: OnceLock::new(),
service: self.service.clone(), service: Arc::downgrade(self.service),
name, name,
} }
} }