Repository: tikv/tikv
File: src/coprocessor/endpoint.rs (Rust)

Code before:
                // Sleep here to simulate slow snapshot retrieval that causes timeout
                // The failpoint can be configured with a sleep duration, e.g.:
                // fail::cfg("coprocessor_async_in_memory_snapshot_timeout",
                // "sleep(500)").unwrap();
                fail_point!("coprocessor_async_in_memory_snapshot_timeout");
            }
            snapshot_future.await
        }
    }

    /// Gets a snapshot with timeout based on the request deadline.
    ///
    /// Safety: This function must be called within a context where a TLS engine
    /// exists.
    async unsafe fn get_snapshot_with_timeout(ctx: &ReqContext) -> Result<E::IMSnap> {
        let snapshot_future = with_tls_engine(|engine| Self::async_in_memory_snapshot(engine, ctx));
        let max_duration_to_get_snapshot = ctx.deadline.remaining_duration();
        if max_duration_to_get_snapshot.is_zero() {
            return Err(Error::DeadlineExceeded);
        }
        match async_timeout(snapshot_future, max_duration_to_get_snapshot).await {
            Ok(snapshot) => snapshot,
            Err(_) => {
                warn!("timeout when getting snapshot";
                    "region_id" => &ctx.context.get_region_id(),
                    "max_duration_to_get_snapshot" => ?max_duration_to_get_snapshot,
                );
                Err(Error::DeadlineExceeded)
            }
        }
    }

    /// The real implementation of handling a unary request.
    ///
    /// It first retrieves a snapshot, then builds the `RequestHandler` over the
    /// snapshot and the given `handler_builder`. Finally, it calls the unary
    /// request interface of the `RequestHandler` to process the request and
    /// produce a result.
    async fn handle_unary_request_impl(
        semaphore: Option<Arc<Semaphore>>,
        mut tracker: Box<Tracker<E>>,
        handler_builder: RequestHandlerBuilder<E::IMSnap>,
    ) -> Result<MemoryTraceGuard<coppb::Response>> {
        with_tls_tracker(|tracker1| {
            record_network_in_bytes(tracker1.metrics.grpc_req_size);
        });
        // When this function is being executed, it may be queued for a long time, so
        // that deadline may exceed.
        tracker.on_scheduled();
        tracker.req_ctx.deadline.check()?;


Review comment (bug):
The timeout error from `async_timeout` is being discarded with `Err(_)` pattern matching. While this is converted to a generic `Error::DeadlineExceeded`, it would be more informative to log the actual timeout error details for debugging purposes. Consider logging the error before converting it, or including more context in the warning message.
```suggestion
            Err(e) => {
                warn!("timeout when getting snapshot";
                    "region_id" => &ctx.context.get_region_id(),
                    "max_duration_to_get_snapshot" => ?max_duration_to_get_snapshot,
                    "error" => ?e,
```

Code after:
            // fail::cfg("coprocessor_async_in_memory_snapshot_timeout",
            // "sleep(500)").unwrap();
            fail_point!("coprocessor_async_in_memory_snapshot_timeout");
            snapshot_future.await
        }
    }

    /// Gets a snapshot with timeout based on the request deadline.
    ///
    /// Safety: This function must be called within a context where a TLS engine
    /// exists.
    async unsafe fn get_snapshot_with_timeout(ctx: &ReqContext) -> Result<E::IMSnap> {
        let snapshot_future = with_tls_engine(|engine| Self::async_in_memory_snapshot(engine, ctx));
        let max_duration_to_get_snapshot = ctx.deadline.remaining_duration();
        if max_duration_to_get_snapshot.is_zero() {
            return Err(Error::DeadlineExceeded);
        }
        match async_timeout(snapshot_future, max_duration_to_get_snapshot).await {
            Ok(snapshot) => snapshot,
            Err(e) => {
                warn!("timeout when getting snapshot";
                    "region_id" => &ctx.context.get_region_id(),
                    "max_duration_to_get_snapshot" => ?max_duration_to_get_snapshot,
                    "err" => ?e,
                );
                Err(Error::DeadlineExceeded)
            }
        }
    }

    /// The real implementation of handling a unary request.
    ///
    /// It first retrieves a snapshot, then builds the `RequestHandler` over the
    /// snapshot and the given `handler_builder`. Finally, it calls the unary
    /// request interface of the `RequestHandler` to process the request and
    /// produce a result.
    async fn handle_unary_request_impl(
        semaphore: Option<Arc<Semaphore>>,
        mut tracker: Box<Tracker<E>>,
        handler_builder: RequestHandlerBuilder<E::IMSnap>,
    ) -> Result<MemoryTraceGuard<coppb::Response>> {
        with_tls_tracker(|tracker1| {
            record_network_in_bytes(tracker1.metrics.grpc_req_size);
        });
        // When this function is being executed, it may be queued for a long time, so
        // that deadline may exceed.
        tracker.on_scheduled();
        tracker.req_ctx.deadline.check()?;

        // Safety: spawning this function using a `FuturePool` ensures that a TLS engine
        // exists.