Heim  >  Artikel  >  Backend-Entwicklung  >  Umgang mit der schichtübergreifenden Kontextaufhebung

Umgang mit der schichtübergreifenden Kontextaufhebung

WBOY
WBOYnach vorne
2024-02-05 23:54:07429Durchsuche

Umgang mit der schichtübergreifenden Kontextaufhebung

Frageninhalt

Ich entwickle eine mehrschichtige Backend-API mit Controllern, Diensten, Repositorys usw.

Kontext

Jede Methode in diesen Ebenen verwendet context.Context als ersten Parameter, der den Anforderungskontext enthält. Dies ist praktisch, da jede Methode auf verschiedene anforderungsbezogene Daten zugreifen kann (z. B. Korrelations-ID usw.)

Jeder Anfragekontext hat eine Zeitüberschreitung, die von TimeoutMiddleware unten festgelegt wird:

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
}

Herausforderung

Die Idee besteht darin, alle laufenden Vorgänge ordnungsgemäß zu stoppen, wenn der Anforderungskontext das Zeitlimit überschreitet. Basierend auf meinem (sehr geringen) Verständnis von Kontext und Parallelität habe ich diese Hilfsfunktion erstellt:

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

Theoretisch müsste ich, wenn ich jeden Vorgang so schnell wie möglich stoppen wollte, diese Funktion am Anfang

jeder Methode in der Anwendung aufrufen, etwa so:

func DoSomething(ctx context.Context, ...) resterrors.RestErr {
if err := helpers.HandleContextCancel(ctx); err != nil {
    return resterrors.NewRequestTimeoutError(
        fmt.Errorf("DoSomething: %w", err),
    )
}
// ...
Außerdem weiß ich, dass in dem Repository, das auf die Datenbank zugreift, die meisten Funktionen einen QueryQueryRowExecKontext

benötigen, wie zum Beispiel

..., etwa so: internal_server_error

rows, err := pgclient.GetSession().Query(ctx, query, param1, ...)

Also muss ich jedes Mal, wenn in der Zeile oben ein Fehler auftritt, prüfen, ob der Fehler nicht auf einen Kontextabbruch zurückzuführen ist, anstatt einfach

und eine Fehlermeldung wie diese zurückzugeben: 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),
    )
}

Die Verwendung der Funktion HandleContextCancel scheint etwas überflüssig zu sein. Was denken Sie darüber?

Unwrap() error

Richtige Antwort🎜🎜Sie benötigen die Funktion HandleContextCancel nicht, Sie können einfach Folgendes tun: 🎜
if ctx.Err()!=nil {
  // Context timed out or canceled. Return
  return ctx.Err()
}
🎜Wenn Ihre anderen Fehlerbehandlungsfunktionen diesen Fehler korrekt umschließen (d. h. sie implementieren die 🎜-Methode), können Sie auf der obersten Ebene prüfen, ob der Fehler einen Timeout-/Abbruchfehler enthält, und entscheiden, welche Art von Fehler Sie zurückgeben möchten Sie müssen dies nicht für jedes Level tun 🎜.

Das obige ist der detaillierte Inhalt vonUmgang mit der schichtübergreifenden Kontextaufhebung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen