summaryrefslogtreecommitdiff
diff options
from:
to:
context:
space:
mode:
-rw-r--r--config/config.go2
-rw-r--r--config/config.json1
-rw-r--r--main.go87
3 files changed, 71 insertions, 19 deletions
diff --git a/config/config.go b/config/config.go
index 0b6c4ff..66533a6 100644
--- a/config/config.go
+++ b/config/config.go
@@ -3,6 +3,7 @@ package config
import (
"encoding/json"
"fmt"
+ "log/slog"
"os"
"github.com/go-playground/validator/v10"
@@ -14,6 +15,7 @@ type Config struct {
Output OutputConfig `json:"Output" validate:"required"`
MaxConcurrentJobs int `json:"MaxConcurrentJobs" validate:"required,min=1"`
ForceRewrite bool `json:"ForceRewrite" validate:"required"`
+ LogLevel slog.Level `json:"LogLevel" validate:"required"`
}
type InputConfig struct {
diff --git a/config/config.json b/config/config.json
index 742949f..acf3e02 100644
--- a/config/config.json
+++ b/config/config.json
@@ -1,6 +1,7 @@
{
"ForceRewrite": false,
"MaxConcurrentJobs": 4,
+ "LogLevel": "info",
"Input": {
"Storage": {
"Type": "b2",
diff --git a/main.go b/main.go
index 9d8b625..32ff634 100644
--- a/main.go
+++ b/main.go
@@ -3,7 +3,10 @@ package main
import (
"flag"
"log/slog"
+ "os"
+ "os/signal"
"sync"
+ "syscall"
"github.com/SayaAndy/saya-today-thumbnail-generator/config"
"github.com/SayaAndy/saya-today-thumbnail-generator/internal/client/input"
@@ -12,33 +15,47 @@ import (
)
var (
- configPath = flag.String("c", "config.json", "Path to the configuration file")
+ configPath = flag.String("c", "config.json", "Path to the configuration file")
+ sigTermChan = make(chan os.Signal, 1)
)
func main() {
- flag.Parse()
+ signal.Notify(sigTermChan, os.Interrupt, syscall.SIGTERM)
- slog.Info("starting thumbnail generator...")
- // slog.SetLogLoggerLevel(slog.LevelDebug)
+ flag.Parse()
cfg := &config.Config{}
if err := config.LoadConfig(*configPath, cfg); err != nil {
- panic(err)
+ slog.Error("fail to load configuration", slog.String("error", err.Error()))
+ os.Exit(1)
+ }
+
+ slog.SetLogLoggerLevel(cfg.LogLevel)
+ slog.Info("starting thumbnail generator...")
+
+ select {
+ case <-sigTermChan:
+ slog.Info("exiting due to termination signal")
+ os.Exit(130)
+ default:
}
inputClient, err := input.NewB2InputClient(&cfg.Input)
if err != nil {
- panic(err)
+ slog.Error("fail to initialize input client", slog.String("error", err.Error()))
+ os.Exit(1)
}
outputClient, err := output.NewB2OutputClient(&cfg.Output)
if err != nil {
- panic(err)
+ slog.Error("fail to initialize output client", slog.String("error", err.Error()))
+ os.Exit(1)
}
converter, err := processor.NewWebpProcessor(&cfg.Processor)
if err != nil {
- panic(err)
+ slog.Error("fail to initialize converter", slog.String("error", err.Error()))
+ os.Exit(1)
}
generalLogger := slog.With(
@@ -48,35 +65,59 @@ func main() {
)
generalLogger.Info("initialized clients and processor")
+ select {
+ case <-sigTermChan:
+ generalLogger.Info("exiting due to termination signal")
+ os.Exit(130)
+ default:
+ }
+
files, err := inputClient.Scan()
if err != nil {
- panic(err)
+ generalLogger.Error("fail to scan input files", slog.String("error", err.Error()))
+ os.Exit(1)
}
generalLogger.Info("scanned files", slog.Int("file_count", len(files)))
+ select {
+ case <-sigTermChan:
+ generalLogger.Info("exiting due to termination signal")
+ os.Exit(130)
+ default:
+ }
+
semaphore := make(chan struct{}, cfg.MaxConcurrentJobs)
var wg sync.WaitGroup
wg.Add(len(files))
for i, file := range files {
go func(index int, inputName string) {
- semaphore <- struct{}{}
- defer func() { <-semaphore }()
- defer wg.Done()
-
outputName := converter.DeductOutputPath(inputName)
fileLogger := generalLogger.With(slog.String("input_path", inputName), slog.String("output_path", outputName), slog.Int("file_index", index))
+ threadSigTermChannel := make(chan os.Signal, 1)
+ signal.Notify(threadSigTermChannel, os.Interrupt, syscall.SIGTERM)
+
+ defer func() { <-semaphore }()
+ defer wg.Done()
+ semaphore <- struct{}{}
+ select {
+ case <-threadSigTermChannel:
+ fileLogger.Info("exiting due to termination signal")
+ return
+ default:
+ }
+
inputMetadata, err := inputClient.ReadMetadata(inputName)
if err != nil {
- fileLogger.Error("fail to read metadata of (supposedly existing) input file", slog.String("error", err.Error()))
+ fileLogger.Warn("fail to read metadata of (supposedly existing) input file", slog.String("error", err.Error()))
return
}
if !cfg.ForceRewrite && !outputClient.IsMissing(outputName) {
outputMetadata, err := outputClient.ReadMetadata(outputName)
if err != nil {
- fileLogger.Error("fail to read metadata of (supposedly existing) output file", slog.String("error", err.Error()))
+ fileLogger.Warn("fail to read metadata of (supposedly existing) output file", slog.String("error", err.Error()))
return
}
if inputMetadata.Hash == outputMetadata.HashOriginal {
@@ -88,18 +129,18 @@ func main() {
fileLogger.Info("start to process file")
reader, err := inputClient.GetReader(inputName)
if err != nil {
- fileLogger.Error("fail to get reader for input file", slog.String("error", err.Error()))
+ fileLogger.Warn("fail to get reader for input file", slog.String("error", err.Error()))
return
}
writer, err := outputClient.GetWriter(outputName, inputMetadata)
if err != nil {
- fileLogger.Error("fail to get writer for output file", slog.String("error", err.Error()))
+ fileLogger.Warn("fail to get writer for output file", slog.String("error", err.Error()))
return
}
if err := converter.Process(inputMetadata.ContentType, reader, writer); err != nil {
- fileLogger.Error("fail to convert file", slog.String("error", err.Error()))
+ fileLogger.Warn("fail to convert file", slog.String("error", err.Error()))
return
}
@@ -108,5 +149,13 @@ func main() {
}
wg.Wait()
- generalLogger.Info("all files processed successfully, exiting")
+
+ select {
+ case <-sigTermChan:
+ generalLogger.Info("exiting due to termination signal")
+ os.Exit(130)
+ default:
+ generalLogger.Info("all files processed successfully, exiting")
+ os.Exit(0)
+ }
}