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.