# Services Nodes and applications are composed out of services. These are long running components that may communicate with each other. The standard signature for a service is of the form: ```rust use darkfi::ExecutorPtr; pub struct Service { // ... } impl Service { pub fn new(/* ... */, executor: ExecutorPtr) -> Arc { // ... } pub async fn start(self: Arc) { // ... } pub async fn stop(&self) { } } ``` Both `start()` and `stop()` should return immediately without blocking the caller. Any long running tasks they need to perform should be done using `StoppableTask` (see below). ## `StoppableTask` Services will likely want to start any number of processes. For that you can use `StoppableTask`. For example `ManualSession` looks like this: ```rust pub struct ManualSession { p2p: Weak, connect_slots: Mutex>, // ... } impl ManualSession { pub fn new(p2p: Weak) -> ManualSessionPtr { Arc::new(Self { p2p, connect_slots: Mutex::new(Vec::new()), // ... }) } pub async fn connect(self: Arc, addr: Url) { let ex = self.p2p().executor(); let task = StoppableTask::new(); task.clone().start( self.clone().channel_connect_loop(addr), // Ignore stop handler |_| async {}, Error::NetworkServiceStopped, ex, ); self.connect_slots.lock().await.push(task); } pub async fn stop(&self) { let connect_slots = &*self.connect_slots.lock().await; for slot in connect_slots { slot.stop().await; } } // ... } ``` The method in `start()` is a future that returns `Result<()>`. If you do not want to return a result (for example with long running processes), then simply use the future: ```rust async { foo().await; unreachable!() } ``` ## Communicating Between Services Another tool in our toolbox is the `subscribe()/notify()` paradigm. We can use `system::Subscriber`. Then inside our method we can define a method like so: ```rust pub async fn subscribe_stop(&self) -> Result> { let sub = self.stop_subscriber.clone().subscribe().await; Ok(sub) } // ... // Invoke it like this self.stop_subscriber.notify(Error::ChannelStopped).await; ``` Then the API user can simply do: ``` let stop_sub = channel.subscribe_stop().await?; let err = stop_sub.receive().await; stop_sub.unsubscribe().await; ``` ## Parent-Child Relationships In the async context we are forced to use `Arc`, but often times we want a parent-child relationship where if both parties contain an Arc reference to the other it creates a circular loop. For this case, there is a handy helper called `LazyWeak`. ```rust pub struct Parent { child: Arc, // ... } impl Parent { pub async fn new(/* ... */) -> Arc { let self_ = Arc::new(Self { child: Child::new(), // ... }); self_.child.p2p.init(self_.clone()); // ... self_ } // ... } pub struct Child { pub parent: LazyWeak, // ... } impl ManualSession { pub fn new() -> Arc { Arc::new(Self { parent: LazyWeak::new(), // ... }) } // ... } ``` Otherwise if the relationship is just one way, use `Arc`. For example if doing dependency injection where component B dependent on component A, then we could do: ```rust let comp_a = Foo::new(); let comp_b = Bar::new(comp_a); ```