GOPOSTGRES
go context
- 2 minutes read - 363 wordsUnderstanding context in Golang through Postgres
I was trying to learn Go package context especially with respect to Postgres. On a very high level context provides context to the operation. Yeah, I agree, the previous statement doesn’t really add much value, but hold on I don’t really know how to explain it, rather let’s go over some code. Sometimes its easier to understand by seeing it in action :)
The complete program is here
-
Time based context:
There are two methods.
context.WithTimeout()context.WithDeadline()package main import ( "context" "database/sql" "log" "os" _ "github.com/lib/pq" ) func main() { dsn := "user=postgres dbname=postgres sslmode=disable port=5433 password=replaceit" db, err := sql.Open("postgres", dsn) defer db.Close() if err != nil { log.Fatalf("error opening a connection to database %v", err) } err = db.PingContext(context.Background()) if err != nil { log.Fatalf("error connecting to the database %v", err) } ctx := context.Background() ctx, cancel := context.WithTimeout(ctx, 2000*time.Millisecond) defer cancel() _, err = db.QueryContext(ctx, "select * from generate_series(1, 5000000000)") if err != nil { log.Printf("error querying %v", err) } log.Println("done")ctx := context.Background()creates an empty context.Then
ctx, cancel := context.WithTimeout(ctx, 2000*time.Millisecond)which creates a timed context forctx. When we use that context indb.QueryContextthe context gets cancelled at 2s. Meaning any query taking more than 2s will be stopped. -
Using WithCancel():
package main import ( "context" "database/sql" "log" "os" _ "github.com/lib/pq" ) func main() { dsn := "user=postgres dbname=postgres sslmode=disable port=5433 password=replaceit" db, err := sql.Open("postgres", dsn) defer db.Close() if err != nil { log.Fatalf("error opening a connection to database %v", err) } err = db.PingContext(context.Background()) if err != nil { log.Fatalf("error connecting to the database %v", err) } ctx := context.Background() ctx, cancel := context.WithCancel(ctx) go func() { select { case <-time.After(2000 * time.Millisecond): fmt.Fprint(os.Stderr, "query timed out \n") cancel() } }() _, err = db.QueryContext(ctx, "select * from generate_series(1, 50000000)") cancel()
Achieving the same thing (time out queries which takes more than 2 seconds) but using cancel(). In a separate go routine we checking whether its been 2 seconds and by calling cancel() it cancels the context.
I don’t know is there any preferable method. Certainly for time based contexts, context.WithTimeout() or context.WithDeadline() seems more straightforward.