package httpapi import ( "context" "net/http" "strings" "time" "evobgp/internal/db" "evobgp/internal/jobs" "evobgp/internal/observability" "evobgp/internal/repository" "evobgp/internal/store" "github.com/jackc/pgx/v5/pgxpool" ) // NewCDNHTTPClient returns the shared HTTP client for CDN and preview fetches (PERF-02 / ERR-03). func NewCDNHTTPClient() *http.Client { return &http.Client{Timeout: 45 * time.Second} } // BootstrapWorkers opens the same store.Backend and jobs.Registry as New (without HTTP or bundle keys). // Used by standalone worker binaries (scheduler, ingest, …) that share PostgreSQL with the API. func BootstrapWorkers(ctx context.Context, opts Options) (store.Backend, *jobs.Registry, *pgxpool.Pool, error) { ctx, cancel := context.WithTimeout(ctx, 60*time.Second) defer cancel() var backend store.Backend var pool *pgxpool.Pool if u := strings.TrimSpace(opts.DatabaseURL); u != "" { p, err := db.OpenPostgresPool(ctx, u) if err != nil { return nil, nil, nil, err } pool = p pgbe, err := repository.NewPostgres(ctx, p, opts.SeedDemo) if err != nil { pool.Close() return nil, nil, nil, err } backend = pgbe } else { mem := store.NewMemory() if opts.SeedDemo { mem.SeedDemo() } backend = mem } cdnHTTP := NewCDNHTTPClient() wk := &jobs.Worker{Store: backend, HTTPClient: cdnHTTP} reg := jobs.NewRegistry(wk.Process) wk.Registry = reg if pool != nil { audit := repository.NewJobAuditWriter(pool) reg.SetTerminalHook(func(j *jobs.Job) { if j == nil { return } st := j.Snapshot() status, _ := st["status"].(string) var errMsg *string if e, ok := st["error"].(string); ok && e != "" { errMsg = &e } audit.MarkTerminal(context.Background(), j.TenantID, j.ID, status, errMsg, time.Now().UTC()) }) } observability.RegisterStoreBackend(backend) return backend, reg, pool, nil }