Skip to content

Instantly share code, notes, and snippets.

@dmh2000
Last active February 22, 2024 18:19
Show Gist options
  • Save dmh2000/8e2151d6d06ed8817bf9a8a613c65514 to your computer and use it in GitHub Desktop.
Save dmh2000/8e2151d6d06ed8817bf9a8a613c65514 to your computer and use it in GitHub Desktop.
Is this idiomatic Go for handling nested goroutines with context
package main
import (
"context"
"errors"
"fmt"
"time"
)
/*
main -> A
-> B
*/
// main runs 'A'
func A(ctx context.Context, result chan error) {
// A must run B first, B has its own timeout
y, ycancel := context.WithCancel(ctx)
defer ycancel()
r := make(chan error, 1)
go B(y, r)
if err := <-r; err != nil {
// B failed, return an error
result <- err
fmt.Println("B error:", err)
return
}
// Now run the body of A, it also has a timeout
x, xcancel := context.WithTimeout(ctx, 3*time.Second)
defer xcancel()
// then do A operation
//for {
select {
case <-x.Done():
// context timeout
fmt.Println("A Done")
result <- errors.New("A timeout")
return
case <-time.After(2 * time.Second):
// process
fmt.Println("A")
result <- nil
return
}
//}
}
// A runs B
func B(ctx context.Context, result chan error) {
x, cancel := context.WithTimeout(ctx, 4*time.Second)
defer cancel()
select {
case <-x.Done():
// context timeout
fmt.Println("B Done")
result <- errors.New("B timeout")
return
case <-time.After(3 * time.Second):
// process
fmt.Println("B")
result <- nil
return
}
}
func main() {
result := make(chan error, 1)
ctx := context.Background()
go A(ctx, result)
if err := <-result; err != nil {
fmt.Println("main error:", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment