mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-25 14:59:16 +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)
|
- [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)
|
- [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)
|
- [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)
|
- [Glossary](#glossary)
|
||||||
- [Versioning](#versioning)
|
- [Versioning](#versioning)
|
||||||
- [Credits](#credits)
|
- [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.
|
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
|
## 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/dynamic/themes", strategy.ServeDynamicThemes)
|
||||||
api.GET("/strategies/blocking", strategy.ServeBlocking)
|
api.GET("/strategies/blocking", strategy.ServeBlocking)
|
||||||
}
|
}
|
||||||
|
health := routes.Health{}
|
||||||
|
health.SetDefaults()
|
||||||
|
health.WithContext(ctx)
|
||||||
|
base.GET("/health", health.ServeHTTP)
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := &http.Server{
|
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(startCmd)
|
||||||
rootCmd.AddCommand(versionCmd)
|
rootCmd.AddCommand(versionCmd)
|
||||||
|
|
||||||
|
healthCmd.Flags().String("url", "http://localhost:10000/health", "Sablier health endpoint")
|
||||||
|
rootCmd.AddCommand(healthCmd)
|
||||||
|
|
||||||
return rootCmd
|
return rootCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user