Time Limit pattern

Time Limit pattern

Time Limit Pattern là một kỹ thuật đặt giới hạn thời gian chờ xử lý (timeout) cho các yêu cầu (request) hoặc xử lý trong hệ thống, nhằm tránh treo ứng dụng hoặc làm chậm toàn bộ hệ thống do một service phản hồi chậm.

Mục đích chính:

  • Bảo vệ tài nguyên: Ngăn chặn service bị quá tải do chờ response quá lâu.

  • Tăng tốc độ phản hồi: Nếu một request bị treo quá lâu, hệ thống có thể hủy request và xử lý fallback.

  • Cải thiện trải nghiệm người dùng: Hạn chế tình trạng ứng dụng phản hồi chậm.

Ví dụ:

  • API thanh toán chỉ cho phép chờ tối đa 3 giây. Nếu quá thời gian này, hệ thống sẽ hủy yêu cầu và trả về lỗi timeout.

  • Một truy vấn database mất hơn 5 giây sẽ bị hủy để tránh làm chậm các truy vấn khác.

Cơ chế hoạt động

Time Limit hoạt động bằng cách đặt giới hạn thời gian (timeout) cho một quá trình xử lý. Nếu quá thời gian đó mà chưa có phản hồi, hệ thống sẽ hủy yêu cầu và thực hiện fallback hoặc retry.

Các loại Time Limit trong hệ thống

  1. Request Timeout – Giới hạn thời gian phản hồi của API.

  2. Database Query Timeout – Giới hạn thời gian thực thi truy vấn database.

  3. Thread Execution Timeout – Giới hạn thời gian chạy của một luồng.

  4. Asynchronous Task Timeout – Giới hạn thời gian chạy của các tác vụ nền.

Trường hợp sử dụng

  • API Gateway Timeout: Khi một API gọi service khác, cần đặt timeout để không bị treo nếu service backend chậm.

  • Query Database Timeout: Hạn chế thời gian truy vấn để tránh query phức tạp làm quá tải hệ thống.

  • External API Call Timeout: Khi gọi API bên thứ ba, cần đặt timeout để tránh treo nếu API chậm hoặc lỗi.

  • Worker Task Timeout: Nếu một công việc chạy quá lâu, cần hủy để giải phóng tài nguyên.

Cách triển khai

1. Cấu hình Timeout trong API Gateway

Ví dụ cấu hình Timeout với Kong API Gateway:

services:
  - name: my-service
    url: http://backend-service
    connect_timeout: 3000   # 3 giây
    read_timeout: 5000      # 5 giây
    write_timeout: 5000     # 5 giây

Nếu service phản hồi chậm hơn 3 giây, API Gateway sẽ tự động hủy request.

2. Đặt Timeout trong Spring Boot (RestTemplate, WebClient, Feign Client)

Ví dụ cấu hình Timeout với RestTemplate

@Bean
public RestTemplate restTemplate() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(3000); // 3 giây
    factory.setReadTimeout(5000);    // 5 giây
    return new RestTemplate(factory);
}

Nếu API backend phản hồi chậm hơn 3 giây, request sẽ bị hủy.

Ví dụ cấu hình Timeout với WebClient

WebClient webClient = WebClient.builder()
    .baseUrl("http://backend-service")
    .clientConnector(new ReactorClientHttpConnector(
        HttpClient.create().responseTimeout(Duration.ofSeconds(3))
    ))
    .build();

Ví dụ cấu hình Timeout với Feign Client

@FeignClient(name = "backend-service", url = "http://backend-service", configuration = FeignConfig.class)
public interface BackendClient {
    @GetMapping("/data")
    String getData();
}

@Configuration
public class FeignConfig {
    @Bean
    public Request.Options options() {
        return new Request.Options(3000, 5000); // 3s connect, 5s read
    }
}

Nếu gọi API mất quá 3 giây để kết nối hoặc quá 5 giây để đọc dữ liệu, request sẽ bị hủy.

3. Timeout trong Database (PostgreSQL, MySQL, MongoDB)

Ví dụ cấu hình Query Timeout trong PostgreSQL

SET statement_timeout = 5000; -- 5 giây
SELECT * FROM large_table;

Nếu query mất hơn 5 giây, nó sẽ bị hủy

Ví dụ cấu hình Timeout trong Spring Boot (JPA)

spring.datasource.hikari.connection-timeout=3000
spring.datasource.hikari.validation-timeout=5000

Nếu kết nối database mất hơn 3 giây hoặc query lâu hơn 5 giây, nó sẽ bị hủy.

4. Timeout trong Circuit Breaker (Resilience4j)

@Bean
public TimeLimiterConfig timeLimiterConfig() {
    return TimeLimiterConfig.custom()
        .timeoutDuration(Duration.ofSeconds(3)) // 3 giây timeout
        .build();
}

Nếu một service mất hơn 3 giây để phản hồi, Circuit Breaker sẽ hủy request.

5. Timeout trong Asynchronous Tasks (ExecutorService, CompletableFuture)

Timeout với ExecutorService

ExecutorService executor = Executors.newFixedThreadPool(10);
Future<String> future = executor.submit(() -> callSlowService());

try {
    String result = future.get(3, TimeUnit.SECONDS); // Timeout sau 3 giây
} catch (TimeoutException e) {
    System.out.println("Request timeout!");
}

Nếu service phản hồi chậm hơn 3 giây, request sẽ bị hủy.

Timeout với CompletableFuture

CompletableFuture.supplyAsync(() -> callSlowService())
    .orTimeout(3, TimeUnit.SECONDS)
    .exceptionally(ex -> "Fallback response");

Nếu service mất hơn 3 giây, nó sẽ trả về fallback.