Process lifecycle management

This commit is contained in:
2024-10-02 11:18:36 +08:00
parent f66f144f2e
commit ae12eb2a15
9 changed files with 221 additions and 13 deletions

View File

@@ -15,8 +15,5 @@ func InitializeWarden(regions []*Region) {
// Hot swap
warden.InstancePool = pool
for _, instance := range warden.InstancePool {
instance.Wake()
}
warden.StartPool()
}

View File

@@ -8,8 +8,13 @@ import (
)
func getApplications(c *fiber.Ctx) error {
applications := lo.FlatMap(navi.R.Regions, func(item *navi.Region, idx int) []warden.Application {
return item.Applications
applications := lo.FlatMap(navi.R.Regions, func(item *navi.Region, idx int) []warden.ApplicationInfo {
return lo.Map(item.Applications, func(item warden.Application, index int) warden.ApplicationInfo {
return warden.ApplicationInfo{
Application: item,
Status: warden.GetFromPool(item.ID).Status,
}
})
})
return c.JSON(applications)
@@ -24,3 +29,45 @@ func getApplicationLogs(c *fiber.Ctx) error {
return c.SendString(instance.Logs())
}
}
func letApplicationStart(c *fiber.Ctx) error {
if instance, ok := lo.Find(warden.InstancePool, func(item *warden.AppInstance) bool {
return item.Manifest.ID == c.Params("id")
}); !ok {
return fiber.NewError(fiber.StatusNotFound)
} else {
if err := instance.Wake(); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}
}
func letApplicationStop(c *fiber.Ctx) error {
if instance, ok := lo.Find(warden.InstancePool, func(item *warden.AppInstance) bool {
return item.Manifest.ID == c.Params("id")
}); !ok {
return fiber.NewError(fiber.StatusNotFound)
} else {
if err := instance.Stop(); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}
}
func letApplicationRestart(c *fiber.Ctx) error {
if instance, ok := lo.Find(warden.InstancePool, func(item *warden.AppInstance) bool {
return item.Manifest.ID == c.Params("id")
}); !ok {
return fiber.NewError(fiber.StatusNotFound)
} else {
if err := instance.Stop(); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
if err := instance.Start(); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}
}

View File

@@ -49,6 +49,9 @@ func InitSideload() *fiber.App {
cgi.Get("/regions/cfg/:id", getRegionConfig)
cgi.Get("/applications", getApplications)
cgi.Get("/applications/:id/logs", getApplicationLogs)
cgi.Post("/applications/:id/start", letApplicationStart)
cgi.Post("/applications/:id/stop", letApplicationStop)
cgi.Post("/applications/:id/restart", letApplicationRestart)
cgi.Post("/reload", doReload)
}

View File

@@ -2,10 +2,11 @@ package warden
import (
"fmt"
"os"
"github.com/rs/zerolog/log"
"os/exec"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/samber/lo"
@@ -87,15 +88,16 @@ func (v *AppInstance) Start() error {
// Monitor
go func() {
for {
if v.Cmd.Process == nil || v.Cmd.ProcessState == nil {
if v.Cmd != nil && v.Cmd.Process == nil {
v.Status = AppStarting
} else if !v.Cmd.ProcessState.Exited() {
} else if v.Cmd != nil && v.Cmd.ProcessState == nil {
v.Status = AppStarted
} else {
v.Status = lo.Ternary(v.Cmd.ProcessState.Success(), AppExited, AppFailure)
v.Status = lo.Ternary(v.Cmd == nil, AppExited, AppFailure)
v.Cmd = nil
return
}
time.Sleep(100 * time.Millisecond)
time.Sleep(1000 * time.Millisecond)
}
}()
@@ -104,8 +106,13 @@ func (v *AppInstance) Start() error {
func (v *AppInstance) Stop() error {
if v.Cmd != nil && v.Cmd.Process != nil {
if err := v.Cmd.Process.Signal(os.Interrupt); err != nil {
v.Cmd.Process.Kill()
if err := v.Cmd.Process.Signal(syscall.SIGTERM); err != nil {
log.Warn().Int("pid", v.Cmd.Process.Pid).Err(err).Msgf("Failed to send SIGTERM to process...")
if err = v.Cmd.Process.Kill(); err != nil {
log.Error().Int("pid", v.Cmd.Process.Pid).Err(err).Msgf("Failed to kill process...")
} else {
v.Cmd = nil
}
return err
} else {
v.Cmd = nil

View File

@@ -6,3 +6,8 @@ type Application struct {
Command []string `json:"command" toml:"command"`
Environment []string `json:"environment" toml:"environment"`
}
type ApplicationInfo struct {
Application
Status AppStatus `json:"status"`
}