mirror of
https://github.com/hanzoai/service-template.git
synced 2026-10-30 18:22:53 +00:00
github.com/hanzoai/template existed only as loose files: no .git, no history, no remote. Sweeps that look for a .git directory could not see it, and an rm -rf would have destroyed it with nothing to recover from. Committed as-is; no source modified. NOTE: no remote. This is still one copy in one place.
76 lines
1.9 KiB
Go
76 lines
1.9 KiB
Go
// Command appd is the long-running HTTP daemon for the template service.
|
|
//
|
|
// Boot sequence:
|
|
//
|
|
// 1. Load env config.
|
|
// 2. Assert the service is behind hanzoai/gateway (HANZO_GATEWAY_UPSTREAM=1).
|
|
// If not, boot refuses — the service NEVER verifies JWT itself.
|
|
// 3. Build the per-(org,user) store.
|
|
// 4. Wire the mux.
|
|
// 5. Listen. On SIGTERM: flush every dirty SQLite, then exit.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/hanzoai/base/tools/claims"
|
|
"github.com/hanzoai/template/api"
|
|
"github.com/hanzoai/template/config"
|
|
"github.com/hanzoai/template/store"
|
|
)
|
|
|
|
func main() {
|
|
if err := claims.AssertGatewayUpstream(); err != nil {
|
|
log.Fatalf("boot: %v", err)
|
|
}
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
log.Fatalf("boot: %v", err)
|
|
}
|
|
|
|
mts, err := store.New(cfg)
|
|
if err != nil {
|
|
log.Fatalf("boot: %v", err)
|
|
}
|
|
|
|
// Wire the real per-(org,user) store. *base.MultiTenantStore
|
|
// satisfies api.AppStore via its ForCtx(context.Context) signature.
|
|
app := &api.App{Store: mts}
|
|
|
|
srv := &http.Server{
|
|
Addr: cfg.ListenAddr,
|
|
Handler: api.Router(app),
|
|
ReadHeaderTimeout: 5 * time.Second,
|
|
}
|
|
|
|
// Graceful shutdown — flush stores before exit.
|
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
go func() {
|
|
log.Printf("listening on %s", cfg.ListenAddr)
|
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("serve: %v", err)
|
|
}
|
|
}()
|
|
|
|
<-ctx.Done()
|
|
log.Printf("shutdown: draining HTTP")
|
|
shutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
_ = srv.Shutdown(shutCtx)
|
|
|
|
log.Printf("shutdown: flushing tenant stores")
|
|
if err := mts.Close(shutCtx); err != nil {
|
|
log.Printf("shutdown: store close: %v", err)
|
|
}
|
|
log.Printf("shutdown: done")
|
|
os.Exit(0)
|
|
}
|