pub async fn run(mut self, mut stop_receiver: watch::Receiver<bool>) -> anyhow::Result<()> {
        self.metrics.observe_info(&self);
        self.health_updater
            .update(Health::from(HealthStatus::Ready));
        let mut last_updated_l1_batch = None;

        while !*stop_receiver.borrow_and_update() {
            let step_outcome = self.step().await;
            self.metrics.observe_step_outcome(step_outcome.as_ref());
            let need_to_sleep = match step_outcome {
                Ok(StepOutcome::UpdatedBatch(batch_number)) => {
                    #[cfg(test)]
                    self.updates_sender.send(batch_number).ok();

                    last_updated_l1_batch = Some(batch_number);
                    self.update_health(last_updated_l1_batch);
                    false
                }
                Ok(StepOutcome::NoProgress | StepOutcome::RemoteHashMissing) => {
                    // Update health status even if no progress was made to timely clear a previously set
                    // "affected" health.
                    self.update_health(last_updated_l1_batch);
                    true
                }
                Ok(StepOutcome::PossibleReorg) => {
                    tracing::info!("Potential chain reorg detected by tree data fetcher; not updating tree data");
                    // Since we don't trust the reorg logic in the tree data fetcher, we let it continue working
                    // so that, if there's a false positive, the whole node doesn't crash (or is in a crash loop in the worst-case scenario).
                    let health = TreeDataFetcherHealth::Affected {
                        error: "Potential chain reorg".to_string(),
                    };
                    self.health_updater.update(health.into());
                    true
                }
                Err(err) if err.is_retriable() => {
                    tracing::warn!(
                        "Transient error in tree data fetcher, will retry after a delay: {err:?}"
                    );
                    let health = TreeDataFetcherHealth::Affected {
                        error: err.to_string(),
                    };
                    self.health_updater.update(health.into());
                    true
                }
                Err(err) => {
                    tracing::error!("Fatal error in tree data fetcher: {err:?}");
                    return Err(err.into());
                }
            };

            if need_to_sleep
                && tokio::time::timeout(self.poll_interval, stop_receiver.changed())
                    .await
                    .is_ok()
            {
                break;
            }
        }
        tracing::info!("Stop request received; tree data fetcher is shutting down");
        Ok(())
    }
Runs this component until a fatal error occurs or a stop request is received. Retriable errors
(e.g., no network connection) are handled gracefully by retrying after a delay.
core/node/node_sync/src/tree_data_fetcher/mod.rs