Maison  >  Article  >  développement back-end  >  Gestion de l'annulation de contexte multicouche

Gestion de l'annulation de contexte multicouche

WBOY
WBOYavant
2024-02-05 23:54:07476parcourir

Gestion de lannulation de contexte multicouche

Contenu de la question

Je développe une API backend en couches avec des contrôleurs, des services, des référentiels, etc.

Contexte

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
}

Défi

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 QueryQueryRowExeccontexte

, tel que

..., 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

Bonne réponse🎜🎜Vous n'avez pas besoin de la fonction 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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer