Question about the usage of Context?

Please see the following code. This is a piece of code that simulates database operations with a loop inside.

In this loop, each database operation requires a timeout context of 2 seconds.

My question is that when the number of loops is very large, the 12th line will create a lot of contexts, and the 13th line will leave a lot of defer codes to be executed. Is this the proper way to use Context? Is there a better solution?

ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 
defer cancel()
// Fetch data (maybe more than 8000 rows) from database
rows, err := db.QueryContext(ctx,"......") // Please ignore the specific SQL statement and args. 
if err != nil {
    // error handle 
}
defer rows.Close()

// handle each row in this loop 
for rows.Next() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) // Line 11
    defer cancel()  //Line 12
    _, err := db.ExecContext(ctx, "......") // Please ignore the specific SQL statement and args. 
    if err != nil {
        // error handle 
    }
    //... 
}

I believe a reasonable next step is to just put the body of the for rows.Next() { ... } loop into its own function. The simplest thing would be to just wrap it into a func() { ... }() immediately-invoked closure to force the defers to run after each iteration:

// handle each row in this loop 
for rows.Next() {
    func() {
        ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) // Line 11
        defer cancel()  //Line 12
        _, err := db.ExecContext(ctx, "......") // Please ignore the specific SQL statement and args. 
        if err != nil {
            // error handle 
        }
        //... 
    }() // immediately invoked closure causes `defer` to run each loop
        // iteration.
}

Depending on the complexity within the // ... comments, it may make more sense to move the block in the loop into its own function or functions.

All that being said…

I’d ask: Why are you calling ExecContext in a loop over QueryContext results? Isn’t there a JOIN or some other construct within the RDBMS where you could do this? This looks like an n + 1 query to me.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.