mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-21 13:23:03 +01:00
feat: add healthcheck capabilities
This commit is contained in:
25
README.md
25
README.md
@@ -29,6 +29,9 @@ Which allows you to start your containers on demand and shut them down automatic
|
||||
- [Creating your own loading theme](#creating-your-own-loading-theme)
|
||||
- [Blocking the loading until the session is ready](#blocking-the-loading-until-the-session-is-ready)
|
||||
- [Saving the state to a file](#saving-the-state-to-a-file)
|
||||
- [Sablier Healthcheck](#sablier-healthcheck)
|
||||
- [Using the `/health` route](#using-the-health-route)
|
||||
- [Using the `sablier health` command](#using-the-sablier-health-command)
|
||||
- [Glossary](#glossary)
|
||||
- [Versioning](#versioning)
|
||||
- [Credits](#credits)
|
||||
@@ -294,7 +297,29 @@ If the file doesn't exist it will be created, and it will be syned upon exit.
|
||||
|
||||
Loaded instances that expired during the restart won't be changed though, they will simply be ignored.
|
||||
|
||||
## Sablier Healthcheck
|
||||
|
||||
### Using the `/health` route
|
||||
|
||||
You can use the route `/health` to check for healthiness.
|
||||
|
||||
- Returns 200 `OK` when ready
|
||||
- Returns 503 `Service Unavailable` when terminating
|
||||
|
||||
### Using the `sablier health` command
|
||||
|
||||
You can use the command `sablier health` to check for healthiness.
|
||||
|
||||
`sablier health` takes on argument `--url` which defaults to `http://localhost:10000/health`.
|
||||
|
||||
```yml
|
||||
services:
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.2.0
|
||||
healthcheck:
|
||||
test: ["sablier", "health"]
|
||||
interval: 1m30s
|
||||
```
|
||||
|
||||
## Glossary
|
||||
|
||||
|
||||
31
app/http/healthcheck/healthcheck.go
Normal file
31
app/http/healthcheck/healthcheck.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
healthy = true
|
||||
unhealthy = false
|
||||
)
|
||||
|
||||
func Health(url string) (string, bool) {
|
||||
resp, err := http.Get(url)
|
||||
|
||||
if err != nil {
|
||||
return err.Error(), unhealthy
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return err.Error(), unhealthy
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
return string(body), unhealthy
|
||||
}
|
||||
|
||||
return string(body), healthy
|
||||
}
|
||||
33
app/http/routes/health.go
Normal file
33
app/http/routes/health.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Health struct {
|
||||
TerminatingStatusCode int `description:"Terminating status code" json:"terminatingStatusCode,omitempty" yaml:"terminatingStatusCode,omitempty" export:"true"`
|
||||
terminating bool
|
||||
}
|
||||
|
||||
func (h *Health) SetDefaults() {
|
||||
h.TerminatingStatusCode = http.StatusServiceUnavailable
|
||||
}
|
||||
|
||||
func (h *Health) WithContext(ctx context.Context) {
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
h.terminating = true
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *Health) ServeHTTP(c *gin.Context) {
|
||||
statusCode := http.StatusOK
|
||||
if h.terminating {
|
||||
statusCode = h.TerminatingStatusCode
|
||||
}
|
||||
|
||||
c.String(statusCode, http.StatusText(statusCode))
|
||||
}
|
||||
@@ -34,6 +34,10 @@ func Start(serverConf config.Server, strategyConf config.Strategy, sessionManage
|
||||
api.GET("/strategies/dynamic/themes", strategy.ServeDynamicThemes)
|
||||
api.GET("/strategies/blocking", strategy.ServeBlocking)
|
||||
}
|
||||
health := routes.Health{}
|
||||
health.SetDefaults()
|
||||
health.WithContext(ctx)
|
||||
base.GET("/health", health.ServeHTTP)
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
|
||||
25
cmd/health.go
Normal file
25
cmd/health.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/acouvreur/sablier/app/http/healthcheck"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var healthCmd = &cobra.Command{
|
||||
Use: "health",
|
||||
Short: "Calls the health endpoint of a Sablier instance",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
details, healthy := healthcheck.Health(cmd.Flag("url").Value.String())
|
||||
|
||||
if healthy {
|
||||
fmt.Fprintf(os.Stderr, "healthy: %v\n", details)
|
||||
os.Exit(0)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "unhealthy: %v\n", details)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -79,6 +79,9 @@ It provides an integrations with multiple reverse proxies and different loading
|
||||
rootCmd.AddCommand(startCmd)
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
|
||||
healthCmd.Flags().String("url", "http://localhost:10000/health", "Sablier health endpoint")
|
||||
rootCmd.AddCommand(healthCmd)
|
||||
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user