2017-04-10 61 views
4

我正在嘗試處理每個請求的上下文超時。我們有以下服務器結構:使用golang的每個請求上下文超時實現

enter image description here

流程概述:

圍棋服務器:基本上,充當[反向代理]。 2

驗證服務器:檢查請求驗證。

應用服務器:核心請求處理邏輯。

現在,如果授權服務器無法在規定的時間內處理請求,那麼我想關閉內存中的goroutine。

這裏是我的嘗試:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 
defer cancel() 
req, _ := http.NewRequest("GET", authorizationServer, nil) 
req.Header = r.Header 
req.WithContext(ctx) 
res, error := client.Do(req) 
select { 
case <-time.After(10 * time.Second): 
    fmt.Println("overslept") 
case <-ctx.Done(): 
    fmt.Println(ctx.Err()) // prints "context deadline exceeded" 
} 

在這裏,環境就返回爲「期限超過」,如果請求未在規定的時間進行處理。但它會繼續處理該請求並在特定時間內返回響應。那麼如何在超過時間時停止請求流(goroutine)。

雖然我也實現完整的請求需要在60秒內被處理,此代碼:

var netTransport = &http.Transport{ 
    Dial: (&net.Dialer{ 
     Timeout: 60 * time.Second, 
    }).Dial, 
    TLSHandshakeTimeout: 60 * time.Second, 
} 
client := &http.Client{ 
    Timeout: time.Second * 60, 
    Transport: netTransport, 
    CheckRedirect: func(req *http.Request, via []*http.Request) error { 
     return http.ErrUseLastResponse 
    }, 
} 

所以我需要任何單獨的上下文實現呢?預先感謝您的幫助。

Note1:如果我們可以使用上下文管理由HTTP服務器創建的每個請求(goroutine)的超時值,那將會很棒。

回答

6

您的代碼中發生的情況非常正確,並且按預期行事。

您創建了一個帶有5 seconds超時的上下文。您將它傳遞給request並提出請求。假設該請求在2秒內返回。然後執行select並等待10秒鐘或等待上下文完成。上下文將始終在創建時的最初5秒內完成,並且每次達到結尾時都會出現該錯誤。

context獨立於請求,它將達到它的最後期限,除非之前取消。當功能完成時使用defer取消請求。

在您的代碼中,請求會將您的超時考慮在內。但ctx.Err()將在每次達到超時時返回deadline exceeded。因爲這是context內發生的事情。多次調用ctx.Err()將返回相同的錯誤。

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 
defer cancel() 

go func() { 
    select { 
    case <-time.After(10 * time.Second): 
     fmt.Println("overslept") 
    case <-ctx.Done(): 
     fmt.Println(ctx.Err()) // prints "context deadline exceeded" 
    } 
}() 
req, _ := http.NewRequest("GET", authorizationServer, nil) 
req.Header = r.Header 
req = req.WithContext(ctx) 
res, error := client.Do(req) 

從上下文文檔:

// Err returns a non-nil error value after Done is closed. Err returns 
// Canceled if the context was canceled or DeadlineExceeded if the 
// context's deadline passed. No other values for Err are defined. 
// After Done is closed, successive calls to Err return the same value. 

在你的代碼,超時將始終達到,而不是取消,這就是爲什麼你收到DeadlineExceeeded。你的代碼是正確的,除了選擇的部分將阻塞,直到10秒通過或上下文超時達到。在你的情況下總是達到上下文超時。

您應該檢查client.Do返回的error而不用擔心這裏的context錯誤。你是控制上下文的人。如果請求超時,那麼當然應該測試一個案例,那麼將會返回一個適當的錯誤供您驗證。

+0

感謝您的回答。它按預期工作。但是我們也有請求處理的reverse_proxy。您能否更新帶有上下文的反向代理的答案? – Avinash

+0

你應該嘗試自己實現它。這樣你可能會明白髮生了什麼事。如果你失敗,那麼你來堆棧溢出。我們不在這裏做你的工作。我們在這裏幫你做好你的工作:D –

+1

哈哈,我已經完成了這些任務。感謝您去內部澄清。 – Avinash