90 lines
2.3 KiB
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
|
|
}
|