Comment gérer les délais d'expiration et les annulations de base de données dans Go

Ici présente principalement le contexte de la demande, mais il y a quelques points à noter. Si vous utilisez un middleware, vous aurez besoin que toutes les demandes soient traitées. Avez-vous besoin de cela? Faites également attention au writetimeout de resp, sinon si le timeout de la requête dans le traitement sql est supérieur à w, il est fondamentalement invalide.

 

Non traité, créez d'abord un sql conditionnel

paquet principal

importer (
    " base de données / sql " 
    " fmt " 
    " log " 
    " net / http "

    _ " github.com/lib/pq "
)

var db * sql.DB

erreur func slowQuery () {
    _, err: = db.Exec ( " SELECT pg_sleep (10) " )
     return err
}

func main () {
    erreur d'erreur var

    db, err = sql.Open ( " postgres " , " postgres: // user: pa $$ word @ localhost / example_db " )
     si err! = nil {
        log.Fatal (err)
    }

    si err = db.Ping (); err! = nil {
        log.Fatal (err)
    }

    mux: = http.NewServeMux ()
    mux.HandleFunc ( " / " , exampleHandler)

    log.Println ( " Écoute ... " )
    err = http.ListenAndServe ( " : 5000 " , mux)
     si err! = nil {
        log.Fatal (err)
    }
}

func exampleHandler (w http.ResponseWriter, r * http.Request) {
    err: = slowQuery ()
     si err! = nil {
        serverError (w, err)
        revenir
    }

    fmt.Fprintln (w, " OK " )
}

func serverError (w http.ResponseWriter, erreur err) {
    log.Printf ( " ERREUR:% s " , err.Error ())
    http.Error (w, " Désolé, quelque chose s'est mal passé " , http.StatusInternalServerError)
}

 

 

Plusieurs démos de traitement

paquet principal

importer (
    " context "  // Nouvelle importation 
    " database / sql " 
    " fmt " 
    " log " 
    " net / http " 
    " time "  // Nouvelle importation 

    _ " github.com/lib/pq "
)

var db * sql.DB

erreur func slowQuery (ctx context.Context) {
    // Créez un nouveau contexte enfant avec un délai d'attente de 5 secondes, en utilisant
     // le paramètre ctx fourni comme parent. 
    ctx, cancel: = context.WithTimeout (ctx, 5 * time.Second)
    différer annuler ()

    // Passez le contexte enfant (celui avec le délai) comme premier
     // paramètre à ExecContext (). 
    _, err: = db.ExecContext (ctx, " SELECT pg_sleep (10) " )
     return err
}

...

func exampleHandler (w http.ResponseWriter, r * http.Request) {
     // Passez le contexte de la requête à slowQuery (), afin qu'il puisse être utilisé comme 
     // contexte parent. 
    err: = slowQuery (r.Context ())
     if err! = nil {
        serverError (w, err)
        revenir
    }

    fmt.Fprintln (w, " OK " )
}

...

 

 

paquet principal

importer (
    " context " 
    " database / sql " 
    " errors "  // Nouvelle importation 
    " fmt " 
    " log " 
    " net / http " 
    " time "

    _ " github.com/lib/pq "
)

var db * sql.DB

erreur func slowQuery (ctx context.Context) {
    ctx, cancel: = context.WithTimeout (ctx, 5 * time.Second)
    différer annuler ()

    _, err: = db.ExecContext (ctx, " SELECT pg_sleep (10) " )
     // Si nous obtenons une erreur "pq: canceling statement ...", enveloppez-la avec 
     // l' erreur de contexte avant de retourner. 
    if err! = nil && err.Error () == " pq: instruction d'annulation en raison de la demande de l'utilisateur " {
         return fmt.Errorf ( " % w:% v " , ctx.Err (), err)
    }

    retour err
}

...

func exampleHandler (w http.ResponseWriter, r * http.Request) {
    err: = slowQuery (r.Context ())
     if err! = nil {
         // Vérifiez si l'erreur renvoyée est égale ou enveloppe context.Canceled et 
         // enregistre un avertissement si c'est le cas. 
        switch {
         case errors.Is (err, context.Canceled):
            serverWarning (err)
        par défaut :
            serverError (w, err)
        }
        revenir
    }

    fmt.Fprintln (w, " OK " )
}

func serverWarning (erreur d'erreur) {
    log.Printf ( " AVERTISSEMENT:% s " , err.Error ())
}

...

 

 

...

func main () {
    erreur d'erreur var

    db, err = sql.Open ( " postgres " , " postgres: // user: pa $$ word @ localhost / example_db " )
     si err! = nil {
        log.Fatal (err)
    }

    // Créez un contexte avec un délai d'attente de 10 secondes, en utilisant // context.Background () vide 
     comme parent. 
    ctx, cancel: = context.WithTimeout (context.Background (), 10 * time.Second)
    différer annuler ()

    // Utilisez-le lors du test du pool de connexions. 
    si err = db.PingContext (ctx); err! = nil {
        log.Fatal (err)
    }

    mux: = http.NewServeMux ()
    mux.HandleFunc ( " / " , exampleHandler)

    log.Println ( " Écoute ... " )
    err = http.ListenAndServe ( " : 5000 " , mux)
     si err! = nil {
        log.Fatal (err)
    }
}

...

 

middleware

func setTimeout (suivant http.Handler) http.Handler {
     return http.HandlerFunc (func (w http.ResponseWriter, r * http.Request) {
        ctx, cancel: = context.WithTimeout (r.Context (), 5 * time.Second)
        différer annuler ()

        // Cela vous donne une copie de la demande avec le contexte de la demande 
         // changé pour le nouveau contexte avec le délai d'attente de 5 secondes créé 
         // ci-dessus. 
        r = r.WithContext (ctx)
        next.ServeHTTP (w, r)
    })
}

 

 

Adresse d'origine

https://www.alexedwards.net/blog/how-to-manage-database-timeouts-and-cancellations-in-go

 

L'auteur a écrit très détaillé, le contenu n'est pas difficile.

Je suppose que tu aimes

Origine www.cnblogs.com/CherryTab/p/12757886.html
conseillé
Classement