Maison > Article > développement back-end > Gestion de l'annulation de contexte multicouche
Je développe une API backend en couches avec des contrôleurs, des services, des référentiels, etc.
Chaque méthode de ces couches prend context.Context
comme premier paramètre contenant le contexte de requête. C'est pratique car n'importe quelle méthode peut accéder à diverses données liées à la requête (telles que l'ID de corrélation, etc.)
Chaque contexte de requête a un délai d'attente défini par TimeoutMiddleware
ci-dessous :
func TimeoutMiddleware(timeoutFn func(*gin.Context) time.Duration) gin.HandlerFunc { return func(c *gin.Context) { timeout := timeoutFn(c) ctx, cancel := context.WithTimeout(c.Request.Context(), timeout) defer cancel() c.Request = c.Request.WithContext(ctx) c.Next() } } func TimeoutFn(c *gin.Context) time.Duration { return conf.HTTPRouter.DefaultContextTimeout }
L'idée est d'arrêter gracieusement toutes les opérations en cours lorsque le contexte de la demande expire. Sur la base de ma compréhension du contexte et de la concurrence (très peu), j'ai construit cette fonction d'assistance :
package helpers import "context" // Checks for context cancellation and returns ctx.Err() if canceled. func HandleContextCancel(ctx context.Context) error { select { case <-ctx.Done(): // If the context is canceled return ctx.Err() // return immediately with the canceled error. default: return nil // Continue with the normal processing. } }
Théoriquement, si je voulais arrêter toute opération dès que possible , j'aurais besoin d'appeler cette fonction au début
de chaque méthode de l'application, comme ceci :
func DoSomething(ctx context.Context, ...) resterrors.RestErr {
if err := helpers.HandleContextCancel(ctx); err != nil {
return resterrors.NewRequestTimeoutError(
fmt.Errorf("DoSomething: %w", err),
)
}
// ...
De plus, je sais que dans le référentiel qui accède à la base de données, la plupart des fonctions nécessitent un Query
、QueryRow
、Exec
contexte
..., comme ceci : internal_server_error
rows, err := pgclient.GetSession().Query(ctx, query, param1, ...)Donc, chaque fois qu'une erreur se produit dans la ligne ci-dessus, je dois vérifier si l'erreur n'est pas due à une annulation de contexte au lieu de simplement renvoyer
et un message d'erreur comme celui-ci : HandleContextCancel
函数看起来有点多余,您对此有何看法?
您不需要 HandleContextCancel
rows, err := pgclient.GetSession().Query(ctx, query, param1, ...) if err != nil { return helpers.MapRepoError("DoSomething: Query Error:", err) }
func MapRepoError(location string, err error) resterrors.RestErr { if errors.Is(err, context.DeadlineExceeded) { return resterrors.NewRequestTimeoutError( fmt.Errorf("%s request_timeout", location), ) } return resterrors.NewInternalServerError( fmt.Errorf("%s %w", location, err), ) }Utiliser la fonction
HandleContextCancel
semble un peu redondant, qu'en pensez-vous ? Unwrap() error
HandleContextCancel
, vous pouvez simplement faire ce qui suit : 🎜
if ctx.Err()!=nil { // Context timed out or canceled. Return return ctx.Err() }🎜Si vos autres fonctions de gestion des erreurs encapsulent correctement cette erreur (c'est-à-dire qu'elles implémentent la méthode 🎜), vous pouvez alors vérifier au niveau supérieur si l'erreur contient une erreur de délai d'attente/d'annulation et décider quel type d'erreur vous souhaitez que vous souhaitiez renvoyer. vous n'êtes pas obligé de faire cela pour tous les niveaux 🎜.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!