From 050c46388f9302c4728d34f76b728befcd5a1238 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 28 Jul 2020 17:38:43 +1000 Subject: [PATCH] fix: Open the endpoints after the config is loaded We get the injected TokioComponent dependency before the config is loaded, so we can't use it to open the endpoints. And we can't define after_config, because we use derive(Component). So we work around these issues by opening the endpoints manually, from the application's after_config. --- zebrad/src/application.rs | 28 ++++++++++++++++++++++++++++ zebrad/src/components/metrics.rs | 21 +++++++++++++++------ zebrad/src/components/tracing.rs | 21 +++++++++++++++------ 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/zebrad/src/application.rs b/zebrad/src/application.rs index b4e21991..2d50e339 100644 --- a/zebrad/src/application.rs +++ b/zebrad/src/application.rs @@ -126,6 +126,10 @@ impl Application for ZebradApp { config: Self::Cfg, command: &Self::Cmd, ) -> Result<(), FrameworkError> { + use crate::components::{ + metrics::MetricsEndpoint, tokio::TokioComponent, tracing::TracingEndpoint, + }; + // Configure components self.state.components.after_config(&config)?; self.config = Some(config); @@ -137,6 +141,30 @@ impl Application for ZebradApp { .get_downcast_mut::() .expect("Tracing component should be available") .reload_filter(level); + + // Work around some issues with dependency injection and configs + let config = self + .config + .clone() + .expect("config was set to Some earlier in this function"); + + let tokio_component = self + .state + .components + .get_downcast_ref::() + .expect("Tokio component should be available"); + + self.state + .components + .get_downcast_ref::() + .expect("Tracing endpoint should be available") + .open_endpoint(&config.tracing, tokio_component); + + self.state + .components + .get_downcast_ref::() + .expect("Metrics endpoint should be available") + .open_endpoint(&config.metrics, tokio_component); } Ok(()) diff --git a/zebrad/src/components/metrics.rs b/zebrad/src/components/metrics.rs index 85d63bf0..67de0ab5 100644 --- a/zebrad/src/components/metrics.rs +++ b/zebrad/src/components/metrics.rs @@ -1,6 +1,6 @@ //! An HTTP endpoint for metrics collection. -use crate::{components::tokio::TokioComponent, prelude::*}; +use crate::{components::tokio::TokioComponent, config::MetricsSection}; use abscissa_core::{Component, FrameworkError}; @@ -17,11 +17,22 @@ impl MetricsEndpoint { Ok(Self {}) } - /// Do setup after receiving a tokio runtime. - pub fn init_tokio(&mut self, tokio_component: &TokioComponent) -> Result<(), FrameworkError> { + /// Tokio endpoint dependency stub. + /// + /// We can't open the endpoint here, because the config has not been loaded. + pub fn init_tokio(&mut self, _tokio_component: &TokioComponent) -> Result<(), FrameworkError> { + Ok(()) + } + + /// Open the metrics endpoint. + /// + /// We can't implement `after_config`, because we use `derive(Component)`. + /// And the ownership rules might make it hard to access the TokioComponent + /// from `after_config`. + pub fn open_endpoint(&self, metrics_config: &MetricsSection, tokio_component: &TokioComponent) { info!("Initializing metrics endpoint"); - let addr = app_config().metrics.endpoint_addr; + let addr = metrics_config.endpoint_addr; // XXX do we need to hold on to the receiver? let receiver = Receiver::builder() @@ -39,7 +50,5 @@ impl MetricsEndpoint { .spawn(endpoint.async_run()); metrics::set_boxed_recorder(Box::new(receiver)).expect("XXX FIXME ERROR CONVERSION"); - - Ok(()) } } diff --git a/zebrad/src/components/tracing.rs b/zebrad/src/components/tracing.rs index 703dca2a..10c9fb48 100644 --- a/zebrad/src/components/tracing.rs +++ b/zebrad/src/components/tracing.rs @@ -1,6 +1,6 @@ //! An HTTP endpoint for dynamically setting tracing filters. -use crate::{components::tokio::TokioComponent, prelude::*}; +use crate::{components::tokio::TokioComponent, config::TracingSection, prelude::*}; use abscissa_core::{Component, FrameworkError}; @@ -28,14 +28,25 @@ impl TracingEndpoint { Ok(Self {}) } - /// Do setup after receiving a tokio runtime. - pub fn init_tokio(&mut self, tokio_component: &TokioComponent) -> Result<(), FrameworkError> { + /// Tokio endpoint dependency stub. + /// + /// We can't open the endpoint here, because the config has not been loaded. + pub fn init_tokio(&mut self, _tokio_component: &TokioComponent) -> Result<(), FrameworkError> { + Ok(()) + } + + /// Open the tracing endpoint. + /// + /// We can't implement `after_config`, because we use `derive(Component)`. + /// And the ownership rules might make it hard to access the TokioComponent + /// from `after_config`. + pub fn open_endpoint(&self, tracing_config: &TracingSection, tokio_component: &TokioComponent) { info!("Initializing tracing endpoint"); let service = make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(request_handler)) }); - let addr = app_config().tracing.endpoint_addr; + let addr = tracing_config.endpoint_addr; tokio_component .rt @@ -58,8 +69,6 @@ impl TracingEndpoint { error!("Server error: {}", e); } }); - - Ok(()) } }