// This example uses only local HTTP and simulated work; no external services. package main import ( "context" "errors" "flag" "io" "log" "os" "os/signal" "syscall" "time" omni "git.yuntuo.hk/k2safe/go-omni" "git.yuntuo.hk/k2safe/go-omni/lifecycle" ) func main() { address := flag.String("addr", "127.0.0.1:8080", "local listen address") flag.Parse() ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() if err := run(ctx, *address); err != nil { log.Print(err) os.Exit(1) } } func run(ctx context.Context, address string) (runErr error) { deps := lifecycle.NewRuntime(ctx) deps.OnClose(func() error { log.Print("shared resource closed after requests completed"); return nil }) defer func() { runErr = deps.Finish(runErr) }() app := omni.New(omni.WithHTTPConfig(omni.HTTPConfig{ DefaultMaxBodyBytes: 1 << 20, MaxBodyBytes: 20 << 20, ShutdownCancelTimeout: time.Second, }), omni.WithShutdownTimeout(time.Second)) defer func() { runErr = errors.Join(runErr, app.Close()) }() app.HandleWithBodyLimit("POST", "/upload", 16<<20, nil, func(c *omni.Context) error { n, err := io.Copy(io.Discard, c.Request().Body) if err != nil { return err } return c.OK(map[string]int64{"bytes": n}) }) app.GET("/work", func(c *omni.Context) error { log.Print("request accepted") select { case <-time.After(10 * time.Second): return c.OK("finished") case <-c.Context().Done(): // Simulate bounded rollback/cleanup after cancellation. Dependencies // remain available until this handler and its defers have returned. time.Sleep(100 * time.Millisecond) log.Print("request cleanup completed") return c.Context().Err() } }) log.Printf("listening on %s; POST /upload or GET /work, then Ctrl-C", address) return app.RunContext(deps.Context(), address) }