add caching
This commit is contained in:
@@ -7,22 +7,28 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
|
||||
type ApiService struct {
|
||||
repository *repository.ApiRepository
|
||||
serverRepository *repository.ServerRepository
|
||||
serverService *ServerService
|
||||
serverService *ServerService
|
||||
statusCache *model.ServerStatusCache
|
||||
}
|
||||
|
||||
func NewApiService(repository *repository.ApiRepository,
|
||||
serverRepository *repository.ServerRepository,) *ApiService {
|
||||
serverRepository *repository.ServerRepository) *ApiService {
|
||||
return &ApiService{
|
||||
repository: repository,
|
||||
serverRepository: serverRepository,
|
||||
statusCache: model.NewServerStatusCache(model.CacheConfig{
|
||||
ExpirationTime: 30 * time.Second, // Cache expires after 30 seconds
|
||||
ThrottleTime: 5 * time.Second, // Minimum 5 seconds between checks
|
||||
DefaultStatus: model.StatusRunning, // Default to running if throttled
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +41,22 @@ func (as ApiService) GetStatus(ctx *fiber.Ctx) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
status, err := as.StatusServer(serviceName)
|
||||
|
||||
return status, err
|
||||
// Try to get status from cache
|
||||
if status, shouldCheck := as.statusCache.GetStatus(serviceName); !shouldCheck {
|
||||
return status.String(), nil
|
||||
}
|
||||
|
||||
// If cache miss or expired, check actual status
|
||||
statusStr, err := as.StatusServer(serviceName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Parse and update cache with new status
|
||||
status := model.ParseServiceStatus(statusStr)
|
||||
as.statusCache.UpdateStatus(serviceName, status)
|
||||
return status.String(), nil
|
||||
}
|
||||
|
||||
func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) {
|
||||
@@ -45,7 +64,19 @@ func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return as.StartServer(serviceName)
|
||||
|
||||
// Update status cache for this service before starting
|
||||
as.statusCache.UpdateStatus(serviceName, model.StatusStarting)
|
||||
|
||||
statusStr, err := as.StartServer(serviceName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Parse and update cache with new status
|
||||
status := model.ParseServiceStatus(statusStr)
|
||||
as.statusCache.UpdateStatus(serviceName, status)
|
||||
return status.String(), nil
|
||||
}
|
||||
|
||||
func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
|
||||
@@ -53,7 +84,19 @@ func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return as.StopServer(serviceName)
|
||||
|
||||
// Update status cache for this service before stopping
|
||||
as.statusCache.UpdateStatus(serviceName, model.StatusStopping)
|
||||
|
||||
statusStr, err := as.StopServer(serviceName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Parse and update cache with new status
|
||||
status := model.ParseServiceStatus(statusStr)
|
||||
as.statusCache.UpdateStatus(serviceName, status)
|
||||
return status.String(), nil
|
||||
}
|
||||
|
||||
func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
|
||||
@@ -61,7 +104,19 @@ func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return as.RestartServer(serviceName)
|
||||
|
||||
// Update status cache for this service before restarting
|
||||
as.statusCache.UpdateStatus(serviceName, model.StatusRestarting)
|
||||
|
||||
statusStr, err := as.RestartServer(serviceName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Parse and update cache with new status
|
||||
status := model.ParseServiceStatus(statusStr)
|
||||
as.statusCache.UpdateStatus(serviceName, status)
|
||||
return status.String(), nil
|
||||
}
|
||||
|
||||
func (as ApiService) StatusServer(serviceName string) (string, error) {
|
||||
@@ -99,7 +154,12 @@ func ManageService(serviceName string, action string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.ReplaceAll(output, "\x00", ""), nil
|
||||
// Clean up NSSM output by removing null bytes and trimming whitespace
|
||||
cleaned := strings.TrimSpace(strings.ReplaceAll(output, "\x00", ""))
|
||||
// Remove \r\n from status strings
|
||||
cleaned = strings.TrimSuffix(cleaned, "\r\n")
|
||||
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
func (as ApiService) GetServiceName(ctx *fiber.Ctx) (string, error) {
|
||||
|
||||
@@ -9,65 +9,76 @@ import (
|
||||
|
||||
type LookupService struct {
|
||||
repository *repository.LookupRepository
|
||||
cache *model.LookupCache
|
||||
}
|
||||
|
||||
func NewLookupService(repository *repository.LookupRepository) *LookupService {
|
||||
return &LookupService{
|
||||
repository: repository,
|
||||
cache: model.NewLookupCache(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetTracks
|
||||
// Gets Tracks rows from Lookup table.
|
||||
//
|
||||
// Args:
|
||||
// context.Context: Application context
|
||||
// Returns:
|
||||
// string: Application version
|
||||
func (as LookupService) GetTracks(ctx *fiber.Ctx) *[]model.Track {
|
||||
return as.repository.GetTracks(ctx.UserContext())
|
||||
func (s *LookupService) GetTracks(ctx *fiber.Ctx) (interface{}, error) {
|
||||
if cached, exists := s.cache.Get("tracks"); exists {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
tracks := s.repository.GetTracks(ctx.UserContext())
|
||||
s.cache.Set("tracks", tracks)
|
||||
return tracks, nil
|
||||
}
|
||||
|
||||
// GetCarModels
|
||||
// Gets CarModels rows from Lookup table.
|
||||
//
|
||||
// Args:
|
||||
// context.Context: Application context
|
||||
// Returns:
|
||||
// model.LookupModel: Lookup object from database.
|
||||
func (as LookupService) GetCarModels(ctx *fiber.Ctx) *[]model.CarModel {
|
||||
return as.repository.GetCarModels(ctx.UserContext())
|
||||
func (s *LookupService) GetCarModels(ctx *fiber.Ctx) (interface{}, error) {
|
||||
if cached, exists := s.cache.Get("cars"); exists {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
cars := s.repository.GetCarModels(ctx.UserContext())
|
||||
s.cache.Set("cars", cars)
|
||||
return cars, nil
|
||||
}
|
||||
|
||||
// GetDriverCategories
|
||||
// Gets DriverCategories rows from Lookup table.
|
||||
//
|
||||
// Args:
|
||||
// context.Context: Application context
|
||||
// Returns:
|
||||
// model.LookupModel: Lookup object from database.
|
||||
func (as LookupService) GetDriverCategories(ctx *fiber.Ctx) *[]model.DriverCategory {
|
||||
return as.repository.GetDriverCategories(ctx.UserContext())
|
||||
func (s *LookupService) GetDriverCategories(ctx *fiber.Ctx) (interface{}, error) {
|
||||
if cached, exists := s.cache.Get("drivers"); exists {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
categories := s.repository.GetDriverCategories(ctx.UserContext())
|
||||
s.cache.Set("drivers", categories)
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
// GetCupCategories
|
||||
// Gets CupCategories rows from Lookup table.
|
||||
//
|
||||
// Args:
|
||||
// context.Context: Application context
|
||||
// Returns:
|
||||
// model.LookupModel: Lookup object from database.
|
||||
func (as LookupService) GetCupCategories(ctx *fiber.Ctx) *[]model.CupCategory {
|
||||
return as.repository.GetCupCategories(ctx.UserContext())
|
||||
func (s *LookupService) GetCupCategories(ctx *fiber.Ctx) (interface{}, error) {
|
||||
if cached, exists := s.cache.Get("cups"); exists {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
categories := s.repository.GetCupCategories(ctx.UserContext())
|
||||
s.cache.Set("cups", categories)
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
// GetSessionTypes
|
||||
// Gets SessionTypes rows from Lookup table.
|
||||
//
|
||||
// Args:
|
||||
// context.Context: Application context
|
||||
// Returns:
|
||||
// model.LookupModel: Lookup object from database.
|
||||
func (as LookupService) GetSessionTypes(ctx *fiber.Ctx) *[]model.SessionType {
|
||||
return as.repository.GetSessionTypes(ctx.UserContext())
|
||||
func (s *LookupService) GetSessionTypes(ctx *fiber.Ctx) (interface{}, error) {
|
||||
if cached, exists := s.cache.Get("sessions"); exists {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
types := s.repository.GetSessionTypes(ctx.UserContext())
|
||||
s.cache.Set("sessions", types)
|
||||
return types, nil
|
||||
}
|
||||
|
||||
// ClearCache clears all cached lookup data
|
||||
func (s *LookupService) ClearCache() {
|
||||
s.cache.Clear()
|
||||
}
|
||||
|
||||
// PreloadCache loads all lookup data into cache
|
||||
func (s *LookupService) PreloadCache(ctx *fiber.Ctx) {
|
||||
s.GetTracks(ctx)
|
||||
s.GetCarModels(ctx)
|
||||
s.GetDriverCategories(ctx)
|
||||
s.GetCupCategories(ctx)
|
||||
s.GetSessionTypes(ctx)
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (as ServerService) GetAll(ctx *fiber.Ctx, filter *model.ServerFilter) (*[]m
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
(*servers)[i].Status = model.ServiceStatus(status)
|
||||
(*servers)[i].Status = model.ParseServiceStatus(status)
|
||||
instance, ok := as.instances.Load(server.ID)
|
||||
if !ok {
|
||||
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
|
||||
@@ -176,7 +176,7 @@ func (as ServerService) GetById(ctx *fiber.Ctx, serverID int) (*model.Server, er
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
server.Status = model.ServiceStatus(status)
|
||||
server.Status = model.ParseServiceStatus(status)
|
||||
instance, ok := as.instances.Load(server.ID)
|
||||
if !ok {
|
||||
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"acc-server-manager/local/repository"
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"go.uber.org/dig"
|
||||
@@ -21,11 +22,18 @@ func InitializeServices(c *dig.Container) {
|
||||
c.Provide(NewConfigService)
|
||||
c.Provide(NewLookupService)
|
||||
|
||||
err := c.Invoke(func(server *ServerService, api *ApiService, config *ConfigService) {
|
||||
err := c.Invoke(func(server *ServerService, api *ApiService, config *ConfigService, lookup *LookupService) {
|
||||
api.SetServerService(server)
|
||||
config.SetServerService(server)
|
||||
|
||||
// Initialize lookup data using repository directly
|
||||
lookup.cache.Set("tracks", lookup.repository.GetTracks(context.Background()))
|
||||
lookup.cache.Set("cars", lookup.repository.GetCarModels(context.Background()))
|
||||
lookup.cache.Set("drivers", lookup.repository.GetDriverCategories(context.Background()))
|
||||
lookup.cache.Set("cups", lookup.repository.GetCupCategories(context.Background()))
|
||||
lookup.cache.Set("sessions", lookup.repository.GetSessionTypes(context.Background()))
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic("unable to initialize server service in api service")
|
||||
log.Panic("unable to initialize services:", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user