Files
gochat/backend/internal/app/readiness.go
T
Rogeeandrogee 798ea43c2f HH-442: isolate runtime processes and harden shutdown (#90)
* HH-442: isolate runtime processes and harden shutdown

* HH-442: harden worker shutdown races

* HH-442: gate dependency shutdown on active handlers

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-22 02:38:15 +08:00

58 lines
1.7 KiB
Go

package app
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"sync/atomic"
"time"
"github.com/gochat/gochat/internal/config"
"github.com/gochat/gochat/internal/database"
basehandler "github.com/gochat/gochat/internal/handler"
"github.com/gochat/gochat/internal/search"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
func newReadinessChecks(cfg *config.Config, db *gorm.DB, rdb redis.UniversalClient, ready *atomic.Bool) []basehandler.DependencyCheck {
latestMigration, latestMigrationErr := database.LatestVersion(cfg.Database.GetMigrationsPath())
checks := []basehandler.DependencyCheck{
{Name: "redis", Check: func(ctx context.Context) error { return rdb.Ping(ctx).Err() }},
{Name: "migrations", Check: func(ctx context.Context) error {
if latestMigrationErr != nil {
return latestMigrationErr
}
return database.CheckVersion(ctx, db, latestMigration)
}},
{Name: "draining", Check: func(context.Context) error {
if !ready.Load() {
return fmt.Errorf("shutdown in progress")
}
return nil
}},
}
if !strings.EqualFold(cfg.Search.Engine, search.EngineMeilisearch) {
return checks
}
searchClient := &http.Client{Timeout: time.Duration(cfg.Search.TimeoutSeconds) * time.Second}
return append(checks, basehandler.DependencyCheck{Name: "search", Check: func(ctx context.Context) error {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(cfg.Search.Host, "/")+"/health", nil)
if err != nil {
return err
}
response, err := searchClient.Do(request)
if err != nil {
return err
}
defer response.Body.Close()
_, _ = io.Copy(io.Discard, response.Body)
if response.StatusCode != http.StatusOK {
return fmt.Errorf("search health returned %s", response.Status)
}
return nil
}})
}