diff --git a/.env b/.env new file mode 100644 index 0000000..9235376 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +ORBIS_LOG_LEVEL=debug diff --git a/.gitignore b/.gitignore index fcf1a5e..83e7be5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .cuddle/ bin/ +tmp/ diff --git a/cmd/orbis/main.go b/cmd/orbis/main.go index 01b4707..9d7dc61 100644 --- a/cmd/orbis/main.go +++ b/cmd/orbis/main.go @@ -5,9 +5,16 @@ import ( "os" "git.front.kjuulh.io/kjuulh/orbis/internal/app" + "github.com/joho/godotenv" ) func main() { + err := godotenv.Load() + if err != nil { + fmt.Printf("%s\n", err) + os.Exit(1) + } + app := app.NewApp() if err := newRoot(app).Execute(); err != nil { diff --git a/cmd/orbis/root.go b/cmd/orbis/root.go index c377111..4fa72ee 100644 --- a/cmd/orbis/root.go +++ b/cmd/orbis/root.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "git.front.kjuulh.io/kjuulh/orbis/internal/app" "github.com/spf13/cobra" ) @@ -13,8 +15,13 @@ func newRoot(app *app.App) *cobra.Command { Short: "Orbis is a data workflow scheduler for all your batch and real-time needs", RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() logger.Info("starting orbis") + if err := app.Scheduler().Execute(ctx); err != nil { + return fmt.Errorf("scheduler failed with error: %w", err) + } + return nil }, } diff --git a/go.mod b/go.mod index c288e92..56a6702 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require github.com/spf13/cobra v1.8.1 require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect gitlab.com/greyxor/slogor v1.6.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/go.sum b/go.sum index 7bf7282..10298ac 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= diff --git a/internal/app/app.go b/internal/app/app.go index e916092..0e5524b 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,6 +2,8 @@ package app import ( "log/slog" + + "git.front.kjuulh.io/kjuulh/orbis/internal/scheduler" ) type App struct { @@ -17,3 +19,7 @@ func NewApp() *App { func (a *App) Logger() *slog.Logger { return a.logger } + +func (a *App) Scheduler() *scheduler.Scheduler { + return scheduler.NewScheduler(a.logger) +} diff --git a/internal/app/logging.go b/internal/app/logging.go index 75576ac..bf8a3a5 100644 --- a/internal/app/logging.go +++ b/internal/app/logging.go @@ -3,10 +3,26 @@ package app import ( "log/slog" "os" + "strings" "gitlab.com/greyxor/slogor" ) func setupLogging() *slog.Logger { - return slog.New(slogor.NewHandler(os.Stderr)) + logLevelRaw := os.Getenv("ORBIS_LOG_LEVEL") + var logLevel slog.Leveler + switch strings.ToLower(logLevelRaw) { + case "debug": + logLevel = slog.LevelDebug + case "info": + logLevel = slog.LevelInfo + case "warn": + logLevel = slog.LevelWarn + case "error": + logLevel = slog.LevelError + default: + logLevel = slog.LevelInfo + } + + return slog.New(slogor.NewHandler(os.Stderr, slogor.SetLevel(logLevel))) } diff --git a/internal/lifecycles/lifecycles.go b/internal/lifecycles/lifecycles.go new file mode 100644 index 0000000..ad3e0af --- /dev/null +++ b/internal/lifecycles/lifecycles.go @@ -0,0 +1 @@ +package lifecycles diff --git a/internal/scheduler/scheduler.go b/internal/scheduler/scheduler.go new file mode 100644 index 0000000..8897864 --- /dev/null +++ b/internal/scheduler/scheduler.go @@ -0,0 +1,41 @@ +package scheduler + +import ( + "context" + "fmt" + "log/slog" + "time" +) + +type Scheduler struct { + logger *slog.Logger +} + +func NewScheduler(logger *slog.Logger) *Scheduler { + return &Scheduler{ + logger: logger, + } +} + +func (s *Scheduler) Execute(ctx context.Context) error { + for { + select { + case <-ctx.Done(): + s.logger.Info("gracefully shutting down scheduler") + return nil + default: + if err := s.process(ctx); err != nil { + return fmt.Errorf("scheduler failed: %w", err) + } + } + } +} + +func (s *Scheduler) process(ctx context.Context) error { + s.logger.Debug("scheduler processing items") + + // FIXME: simulate work + time.Sleep(time.Second * 5) + + return nil +} diff --git a/internal/utilities/singleton.go b/internal/utilities/singleton.go new file mode 100644 index 0000000..c64cb80 --- /dev/null +++ b/internal/utilities/singleton.go @@ -0,0 +1,25 @@ +package utilities + +import ( + "fmt" + "sync" +) + +func Singleton[T any](init func() (T, error)) func() T { + var ( + once sync.Once + t T + ) + + return func() T { + once.Do(func() { + var err error + t, err = init() + if err != nil { + panic(fmt.Sprintf("creating %T failed: %s", t, err)) + } + }) + + return t + } +} diff --git a/tmp/build-errors.log b/tmp/build-errors.log deleted file mode 100644 index 40b5ed1..0000000 --- a/tmp/build-errors.log +++ /dev/null @@ -1 +0,0 @@ -exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file