Golang Context Deadline và Timeout Là Gì.

Tại sao phải dùng context dealine Một vài trường hợp là khi lập trình các service cần đến deadline mà cần sử dụng phổ biến nhất: Connect đến các loại database như Mysql, Oracle,… Không thể để connect kết nối một thời gian dài, chúng ta cần set đến time để cancel connect . Trường

Tại sao phải dùng context dealine

Một vài trường hợp là khi lập trình các service cần đến deadline mà cần sử dụng phổ biến nhất:

  • Connect đến các loại database như Mysql, Oracle,… Không thể để connect kết nối một thời gian dài, chúng ta cần set đến time để cancel connect .
  • Trường hợp khác đó là connect đến các service bên ngoài thông qua http. Chúng ta cần set time out cũng như deadline cho nó.

Khái niệm

  • Context Dealine được hiểu cách đơn giản là một tính hiệu để huỷ các sự kiện search, query đến cơ sở dữ liệu hoặc các dịch vụ bên ngoài. Ở đây mình sẽ giải thích với deadline còn timeout thực chất cũng là một deadline mà thôi.
  • Khi user nhập /search?q=golang&timeout=1s param timeout 1s là muốn chỉ định server là cancel request sau 1s.

Demo

  • Đầu tiên bạn viết một function dùng để call service bên ngoài, và tốn 1second để xử lý và trả về kết quả.
func callExternalService(w http.ResponseWriter, r *http.Request) {
	time.Sleep(1 * time.Second)
	fmt.Println("response hello")
}
  • Tiếp theo bạn viết func call service bên ngoài và set timeout là 2second cho việc call đó.
func execCall() error {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil)
	if err != nil {
		return err
	}
	ctx, cancel := context.WithTimeout(req.Context(), 2*time.Second)
	defer cancel()
	req = req.WithContext(ctx)
	_, err = client.Do(req)
	return err
}

Ở đây, khi execCall thực thi thì sẽ set timeout cho nó là là 2second, nghĩa là nếu waiting response quá 2second thì sẽ không nhận được kết quả là trả về error luôn.

  • Tiếp đến là hàm main.
func main() {
	go func() {
		http.HandleFunc("/", callExternalService)
		if err := http.ListenAndServe(":8080", nil); err != nil {
			log.Fatal(err)
		}
	}()
	time.Sleep(1 * time.Second) // wait for server to run
	// call server
	err := execCall()
	if errors.Is(err, context.DeadlineExceeded) {
		log.Println("ContextDeadlineExceeded: true")
	}
	if os.IsTimeout(err) {
		log.Println("IsTimeoutError: true")
	}
	if err != nil {
		log.Fatal(err)
	}
}

Sau khi run go run main.go sẽ nhận được kết quả vì callExternalService chỉ thực thi tốn 1second còn timeout2second

response hello

TimeOut
Bây giờ chúng ta sẽ thay đổi func callExternalService và set timout là 3second

func callExternalService(w http.ResponseWriter, r *http.Request) {
	time.Sleep(3 * time.Second)
	fmt.Println("response hello")
}

=> điều này đồng nhiều là timeout của chúng ta sẽ được thực hiện vì hiện tại chỉ có 2second. Kết quả:

ContextDeadlineExceeded: true

IsTimeoutError: true

Get “http://localhost:8080“: context deadline exceeded

Full Code

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ