Files
go-omni/examples/program/main.go

90 lines
2.3 KiB
Go

// Code generated by go-omni project. DO NOT EDIT.
package main
import (
"context"
"errors"
"example.com/program/internal/config"
program "example.com/program/internal/run"
"example.com/program/internal/svc"
"flag"
"fmt"
"git.yuntuo.hk/k2safe/go-omni/lifecycle"
"git.yuntuo.hk/k2safe/go-omni/logx"
"log"
"os"
"os/signal"
"syscall"
)
func main() {
path := flag.String("config", "etc/config.yaml", "configuration file; empty uses Default()")
check := flag.Bool("check-config", false, "validate configuration without initializing dependencies")
flag.Parse()
if *check {
if _, err := config.Load(*path); err != nil {
log.Fatal(err)
}
return
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
if err := run(ctx, *path); err != nil {
log.Fatal(err)
}
}
func run(ctx context.Context, path string) (runErr error) {
cfg, err := config.Load(path)
if err != nil {
return err
}
logger, err := logx.New(cfg.Log)
if err != nil {
return err
}
var deps *svc.ServiceContext
defer func() {
if p := recover(); p != nil {
runErr = fmt.Errorf("program initialization panic: %v", p)
}
if deps != nil {
runErr = deps.Finish(runErr)
}
// Unjoined work may still use its dependencies and logger. The process exits
// unsuccessfully; resource retention never means the work completed.
if !errors.Is(runErr, lifecycle.ErrResourcesRetained) {
runErr = errors.Join(runErr, logger.Close())
}
}()
deps, err = svc.New(ctx, logger, cfg)
if err != nil {
return err
}
if deps.Context().Err() != nil {
return nil
}
done := make(chan struct{})
// This reserved drain proves Run has actually returned, including its defers.
// Runtime bounds the wait even when Run ignores cancellation.
deps.OnDrain("go-omni/project/run", func(context.Context) error { <-done; return nil })
logger.InfoContext(deps.Context(), "program.starting")
go func() {
var result error
returned := false
defer func() {
if p := recover(); p != nil {
result = fmt.Errorf("program run panic: %v", p)
} else if !returned {
result = errors.New("program run exited without returning")
}
deps.RequestShutdown(result)
close(done)
}()
result = program.Run(deps.Context(), deps)
returned = true
}()
<-deps.Context().Done()
return nil
}