graceful shutdown on SIGTERM or SIGINT

This commit is contained in:
milarin 2023-01-19 12:05:46 +01:00
parent 475cb09f5e
commit f63552fa09
3 changed files with 53 additions and 3 deletions

33
main.go
View File

@ -1,16 +1,35 @@
package main package main
import ( import (
"context"
"os"
"os/exec" "os/exec"
"os/signal"
"sync"
"syscall"
"git.milar.in/milarin/channel" "git.milar.in/milarin/channel"
"git.milar.in/nyaanime/logic" "git.milar.in/nyaanime/logic"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
) )
var Runner = InitializeRunner() var (
// AppCtx notifies all threads to finish their work and shutdown
AppCtx, cancelAppCtx = context.WithCancel(context.Background())
// AppExitWg is waiting for all threads until they are done
AppExitWg = &sync.WaitGroup{}
Runner = InitializeRunner()
)
func main() { func main() {
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
go func() {
<-signalChan
exit()
}()
// check for ffprobe in PATH // check for ffprobe in PATH
if _, err := exec.LookPath("ffprobe"); err != nil { if _, err := exec.LookPath("ffprobe"); err != nil {
panic(err) // TODO error handling panic(err) // TODO error handling
@ -35,10 +54,20 @@ func main() {
fileHandleChan := channel.Map(fileChan, NewFileHandle) fileHandleChan := channel.Map(fileChan, NewFileHandle)
workChan, logChan := channel.Tee(fileHandleChan) workChan, logChan := channel.Tee(fileHandleChan)
go channel.Each(workChan, HandleFileInRunner) AppExitWg.Add(1)
go func() {
defer AppExitWg.Done()
channel.Each(workChan, HandleFileInRunner)
}()
channel.Each(logChan, PrintFileHandle) channel.Each(logChan, PrintFileHandle)
} }
func HandleFileInRunner(fh *FileHandle) { func HandleFileInRunner(fh *FileHandle) {
Runner.Run(func() { HandleFile(fh) }) Runner.Run(func() { HandleFile(fh) })
} }
func exit() {
cancelAppCtx() // notify all threads to shutdown
AppExitWg.Wait() // wait for threads until shutdown
}

View File

@ -24,11 +24,22 @@ func InitTelegramBot() error {
} }
TelegramBot = bot TelegramBot = bot
} }
// close channel on app shutdown
go func() {
<-AppCtx.Done()
close(AnimeEpisodeMessageChannel)
}()
AppExitWg.Add(1)
go SendMessagePeriodically() go SendMessagePeriodically()
return nil return nil
} }
func SendMessagePeriodically() { func SendMessagePeriodically() {
defer AppExitWg.Done()
var messagesPerInterval <-chan []model.AnimeEpisode var messagesPerInterval <-chan []model.AnimeEpisode
if TelegramOrganizeMessageSendInterval > 0 { if TelegramOrganizeMessageSendInterval > 0 {

View File

@ -26,7 +26,15 @@ func WatchDirectory(op fsnotify.Op, path string) (<-chan string, error) {
ch := make(chan string, 10) ch := make(chan string, 10)
// close channel on app shutdown
go func() {
<-AppCtx.Done()
watcher.Close()
}()
AppExitWg.Add(1)
go func(watcher *fsnotify.Watcher, ch chan<- string) { go func(watcher *fsnotify.Watcher, ch chan<- string) {
defer AppExitWg.Done()
defer watcher.Close() defer watcher.Close()
for _, file := range files { for _, file := range files {
@ -74,7 +82,9 @@ func WatchDirectory(op fsnotify.Op, path string) (<-chan string, error) {
ch <- event.Name ch <- event.Name
} }
case err, ok := <-watcher.Errors: case err, ok := <-watcher.Errors:
fmt.Println(err, ok) if ok {
fmt.Println(err, ok)
}
close(ch) close(ch)
return return
} }