bianca rosa staff platform engineer @ homeaglow prev: lumos, redhat & stone
package main
import (
"fmt"
"time"
)
const (
N = 10
Seconds = 10
)
func main() {
fmt.Println("Hello world")
for i := 0; i < N; i++ {
fmt.Printf("%d of %d: Scheduling go routine\n", i, N)
go func(i int) {
fmt.Printf("%d of %d: A slow running goroutine started....\n", i, N)
time.Sleep(Seconds * time.Second)
fmt.Printf("%d of %d: A slow running goroutine finished....\n", i, N)
}(i)
}
fmt.Println("Everything has shut down, goodbye")
}
(...)
Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
package main
import (
"fmt"
"time"
)
const (
N = 10
Seconds = 10
)
func main() {
fmt.Println("Hello world")
// criacao das goroutines
time.Sleep(Seconds * time.Second * 2)
fmt.Println("Everything has shut down, goodbye")
}
sync.WaitGroup |
(...)
"To wait for multiple goroutines to finish, we can use a wait group."
var wg sync.WaitGroup
func main() {
fmt.Println("Hello world")
for i := 0; i < N; i++ {
fmt.Printf("%d of %d: Scheduling go routine\n", i, N)
wg.Add(1)
go func(i int) {
fmt.Printf("%d of %d: A slow running goroutine started....\n", i, N)
time.Sleep(Seconds * time.Second)
fmt.Printf("%d of %d: A slow running goroutine finished....\n", i, N)
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("Everything has shut down, goodbye")
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: shutting-down-gracefully
labels:
app: shutting-down-gracefully
spec:
replicas: 1
selector:
matchLabels:
app: shutting-down-gracefully
template:
metadata:
labels:
app: shutting-down-gracefully
spec:
terminationGracePeriodSeconds: 60
containers:
- name: shutting-down-gracefully
image: docker.io/biancarosa/shutting-down-gracefully:v2.0.0
[
{
"name": "string",
"image": "string",
"repositoryCredentials": {
"credentialsParameter": "string"
},
"cpu": integer,
"memory": integer,
"memoryReservation": integer,
...
"startTimeout": integer,
"stopTimeout": integer,
...
}
]
6h não deveria acontecer mas a vida não é o toddynho que a gente toma (ou gostaria de tomar) todo dia de manhã
Containers recebem sinais do SO quando estão sendo encerrados
Conseguimos "escutar" esse sinal do SO através de uma função da std lib do Go
A channel provides a mechanism for concurrently executing functions to communicate by sending and receiving values of a specified element type."
package main
// imports, vars...
func main() {
// criacao das goroutines
gracefulStop := make(chan struct{})
go func() {
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, syscall.SIGINT, syscall.SIGTERM)
<-sigint
wg.Wait()
fmt.Println("Shutting down gracefully...")
close(gracefulStop)
}()
<-gracefulStop
fmt.Println("Everything has shut down, goodbye")
}
gracefulStop := make(chan struct{})
go func() {
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, syscall.SIGINT, syscall.SIGTERM)
<-sigint
// stop consuming messages
// stop http server from receiving reqs
wg.Wait() // or do something else
fmt.Println("Shutting down gracefully...")
close(gracefulStop)
}()
<-gracefulStop
fmt.Println("Everything has shut down, goodbye")
quando o tempo de graceful shutdown não é suficiente
(ou seja, você não pode simplesmente esperar as tasks)
qual é o mínimo que você precisa fazer?
só cuidado com over-engineering
Slides originais (DevConf.CZ 2022)
aprendago.com.br (lista colaborativa) backend engineering adventures
go essentials & descomplicando o go: linuxtips.io