J'essaie de gérer le délai d'expiration du contexte pour chaque demande. Nous avons les structures de serveur suivantes:
Aperçu du flux:
Go Server : Fondamentalement, agit comme un [Reverse-proxy] . 2
Serveur d'authentification : vérifiez l'authentification des demandes.
Serveur d'applications : Logique de traitement des requêtes de base.
Maintenant, si le serveur d'autorisation ne peut pas traiter une demande dans le temps imparti, je veux fermer le goroutine de la mémoire.
Voici ce que j'ai essayé:
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"
}
Ici, le contexte retourne comme " délai dépassé ", si la demande n'est pas traitée dans le délai stipulé. Mais il continue de traiter cette demande et de retourner la réponse plus longtemps que prévu. Alors, comment puis-je arrêter le flux de demande (goroutine), lorsque le temps est dépassé.
Bien que j'aie également implémenté la demande complète, elle doit être traitée en 60 secondes avec ce code:
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
},
}
Ai-je donc également besoin d'implémentations de contexte distinctes? Merci d'avance pour votre aide.
Note1 : Ce sera génial, si nous pouvons gérer le timeout sur chaque requête (goroutine) créée par le serveur HTTP, en utilisant le contexte.
Ce qui se passe dans votre code est très correct et se comporte comme prévu.
Vous créez un contexte avec un délai d'expiration de 5 seconds
. Vous le passez au request
et faites cette demande. Disons que la demande revient en 2 secondes. Vous faites ensuite un select
et attendez 10 secondes ou attendez la fin du contexte. Le contexte se terminera toujours dans les 5 premières secondes de sa création et donnera également cette erreur à chaque fois qu'il atteindra la fin.
Le context
est indépendant de la demande et il atteindra sa date limite, sauf annulation préalable. Vous annulez la demande lorsque la fonction a terminé d'utiliser defer
.
Dans votre code, la demande prend en compte votre délai d'attente. Mais la ctx.Err()
renverra deadline exceeded
Chaque fois qu'elle atteindra le délai d'expiration. Puisque c'est ce qui se passe à l'intérieur du context
. appeler plusieurs fois ctx.Err () renverra la même erreur.
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)
De la documentation contextuelle:
// 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.
Dans votre code, le délai sera toujours atteint et non annulé, c'est pourquoi vous recevez DeadlineExceeeded
. Votre code est correct, sauf la partie sélectionnée qui se bloquera jusqu'à ce que 10 secondes s'écoulent ou que le délai d'expiration du contexte soit atteint. Dans votre cas, le délai d'expiration du contexte est toujours atteint.
Vous devez vérifier le error
renvoyé par l'appel client.Do
Et ne pas vous soucier de l'erreur context
ici. Vous êtes celui qui contrôle le contexte. Si la demande expire, un cas que vous devez tester bien sûr, une erreur appropriée sera retournée pour que vous puissiez la vérifier.