Repository: meilisearch/meilisearch
File: meilisearch/src/middleware.rs (Rust)

Code before:

    fn new_transform(&self, service: S) -> Self::Future {
        ready(Ok(RouteMetricsMiddleware { service, index_scheduler: self.index_scheduler.clone() }))
    }
}

pub struct RouteMetricsMiddleware<S> {
    service: S,
    index_scheduler: Data<IndexScheduler>,
}

impl<S, B> Service<ServiceRequest> for RouteMetricsMiddleware<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    dev::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let mut histogram_timer: Option<HistogramTimer> = None;
        if let Ok(()) = self.index_scheduler.features().and_then(|features| features.check_metrics()) {
            let request_path = req.path();
            let is_registered_resource = req.resource_map().has_resource(request_path);
            if is_registered_resource {
                let request_method = req.method().to_string();
                histogram_timer = Some(
                    crate::metrics::MEILISEARCH_HTTP_RESPONSE_TIME_SECONDS
                        .with_label_values(&[&request_method, request_path])
                        .start_timer(),
                );
                crate::metrics::MEILISEARCH_HTTP_REQUESTS_TOTAL
                    .with_label_values(&[&request_method, request_path])
                    .inc();
            }
        };

        let fut = self.service.call(req);

        Box::pin(async move {
            let res = fut.await?;

            if let Some(histogram_timer) = histogram_timer {
                histogram_timer.observe_duration();
            };
            Ok(res)
        })

Review comment (performance):
`index_scheduler.features()` makes a call to the database to fetch the features and this gets executed before the core logic of the endpoint requested by the user is run.

This can (potentially) cause performance degradation. I had used a `RWLock` in my PR #4128 to prevent this, although I did not write a benchmark test to analyse and compare the different approaches.

@Kerollmops What's your thought on this?

Code after:
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    dev::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let mut histogram_timer: Option<HistogramTimer> = None;

        // calling unwrap here is safe because index scheduler is added to app data while creating actix app.
        // also, the tests will fail if this is not present.
        let index_scheduler = req.app_data::<Data<IndexScheduler>>().unwrap();
        let features = index_scheduler.features();

        if features.check_metrics().is_ok() {
            let request_path = req.path();
            let is_registered_resource = req.resource_map().has_resource(request_path);
            if is_registered_resource {
                let request_method = req.method().to_string();
                histogram_timer = Some(
                    crate::metrics::MEILISEARCH_HTTP_RESPONSE_TIME_SECONDS
                        .with_label_values(&[&request_method, request_path])
                        .start_timer(),
                );
                crate::metrics::MEILISEARCH_HTTP_REQUESTS_TOTAL
                    .with_label_values(&[&request_method, request_path])
                    .inc();
            }
        };

        let fut = self.service.call(req);

        Box::pin(async move {
            let res = fut.await?;

            if let Some(histogram_timer) = histogram_timer {
                histogram_timer.observe_duration();
            };
            Ok(res)
        })
    }
}