Configurable waitforcode

This commit is contained in:
Christopher LaPointe
2023-05-21 10:36:40 -04:00
parent 8afc25766f
commit 7d61ef019a
3 changed files with 37 additions and 23 deletions

View File

@@ -1,6 +1,6 @@
# traefik-lazyloader # traefik-lazyloader
Takes advantage of traefik's router priority to hit this small application that will manage Takes advantage of traefik's router priority to proxy to this small application that will manage
starting/stopping containers to save resources. starting/stopping containers to save resources.
## Quick-Start ## Quick-Start
@@ -9,8 +9,10 @@ starting/stopping containers to save resources.
## Labels ## Labels
* `lazyloader=true` -- Add to containers that should be managed * `lazyloader=true` -- (Required) Add to containers that should be managed
* `lazyloader.stopdelay=5m` -- Amount of time to wait for idle network traffick before stopping a container (default: 5m) * `lazyloader.stopdelay=5m` -- Amount of time to wait for idle network traffick before stopping a container
* `lazyloader.waitforcode=200` -- Waits for this HTTP result from downstream before redirecting user
* `lazyloader.waitforpath=/` -- Checks this path downstream to check for the process being ready, using the `waitforcode`
# Features # Features

View File

@@ -34,7 +34,6 @@
return response.status === {{.WaitForCode}}; return response.status === {{.WaitForCode}};
} }
setInterval(async () => { setInterval(async () => {
console.log("testing...");
if (await testForOk("{{.WaitForPath}}")) { if (await testForOk("{{.WaitForPath}}")) {
console.log("Found! Reloading...") console.log("Found! Reloading...")
location.reload(); location.reload();

51
main.go
View File

@@ -11,6 +11,7 @@ import (
"io/fs" "io/fs"
"net/http" "net/http"
"path" "path"
"strconv"
"strings" "strings"
"time" "time"
@@ -37,10 +38,12 @@ var splashTemplate = template.Must(template.ParseFS(httpAssets, "assets/splash.h
var dockerClient *client.Client var dockerClient *client.Client
type containerState struct { type containerState struct {
Name, ID string Name, ID string
IsRunning bool IsRunning bool
LastWork time.Time LastWork time.Time
StopDelay time.Duration StopDelay time.Duration
WaitForCode int
WaitForPath string
lastRecv, lastSend int64 // Last network traffic, used to see if idle lastRecv, lastSend int64 // Last network traffic, used to see if idle
} }
@@ -167,17 +170,6 @@ func ContainerHandler(w http.ResponseWriter, r *http.Request) {
ct, _ := findContainerByHostname(r.Context(), host) ct, _ := findContainerByHostname(r.Context(), host)
if ct != nil || true { if ct != nil || true {
// TODO: Send response before querying anything about the container (the slow bit)
w.WriteHeader(http.StatusAccepted)
renderErr := splashTemplate.Execute(w, SplashModel{
Name: host,
WaitForCode: 200, // TODO Config-based
WaitForPath: "/",
})
if renderErr != nil {
logrus.Error(renderErr)
}
// Look to start the container // Look to start the container
state := getOrCreateState(ct.ID) state := getOrCreateState(ct.ID)
logrus.Infof("Found container %s for host %s, checking state...", containerShort(ct), host) logrus.Infof("Found container %s for host %s, checking state...", containerShort(ct), host)
@@ -194,6 +186,16 @@ func ContainerHandler(w http.ResponseWriter, r *http.Request) {
state.LastWork = time.Now() state.LastWork = time.Now()
parseContainerSettings(state, ct) parseContainerSettings(state, ct)
} // TODO: What if container crahsed but we think it's started? } // TODO: What if container crahsed but we think it's started?
w.WriteHeader(http.StatusAccepted)
renderErr := splashTemplate.Execute(w, SplashModel{
Name: host,
WaitForCode: state.WaitForCode,
WaitForPath: state.WaitForPath,
})
if renderErr != nil {
logrus.Error(renderErr)
}
} else { } else {
logrus.Warnf("Unable to find container for host %s", host) logrus.Warnf("Unable to find container for host %s", host)
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
@@ -212,14 +214,25 @@ func getOrCreateState(cid string) (ret *containerState) {
func parseContainerSettings(target *containerState, ct *types.Container) { func parseContainerSettings(target *containerState, ct *types.Container) {
{ // Parse stop delay { // Parse stop delay
var stopErr error
stopDelay, _ := labelOrDefault(ct, "stopdelay", "10s") stopDelay, _ := labelOrDefault(ct, "stopdelay", "10s")
target.StopDelay, stopErr = time.ParseDuration(stopDelay) if dur, stopErr := time.ParseDuration(stopDelay); stopErr != nil {
if stopErr != nil { target.StopDelay = 30 * time.Second // TODO: Use config for default
target.StopDelay = 30 * time.Second
logrus.Warnf("Unable to parse stopdelay of %s, defaulting to %s", stopDelay, target.StopDelay.String()) logrus.Warnf("Unable to parse stopdelay of %s, defaulting to %s", stopDelay, target.StopDelay.String())
} else {
target.StopDelay = dur
} }
} }
{ // WaitForCode
codeStr, _ := labelOrDefault(ct, "waitforcode", "200")
if code, err := strconv.Atoi(codeStr); err != nil {
target.WaitForCode = 200
logrus.Warnf("Unable to parse WaitForCode of %s, defaulting to %d", target.Name, target.WaitForCode)
} else {
target.WaitForCode = code
}
}
target.WaitForPath, _ = labelOrDefault(ct, "waitforpath", "/")
} }
func findContainerByHostname(ctx context.Context, hostname string) (*types.Container, error) { func findContainerByHostname(ctx context.Context, hostname string) (*types.Container, error) {