0.2.78
This commit is contained in:
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/ponzischeme89/memby/server/internal/notify"
|
||||
"github.com/ponzischeme89/memby/server/internal/radarr"
|
||||
"github.com/ponzischeme89/memby/server/internal/recommend"
|
||||
"github.com/ponzischeme89/memby/server/internal/runtimestats"
|
||||
"github.com/ponzischeme89/memby/server/internal/scheduler"
|
||||
"github.com/ponzischeme89/memby/server/internal/sonarr"
|
||||
"github.com/ponzischeme89/memby/server/internal/store"
|
||||
@@ -299,11 +300,17 @@ func run(log *slog.Logger, events *logging.Buffer, logLevel *slog.LevelVar) erro
|
||||
return err
|
||||
}
|
||||
sched.SetPaused(server.ActivityPaused)
|
||||
// The ranker calls Tracearr directly on the rebuild path, so it needs the operator's
|
||||
// switch too — read at call time, because an integration switched off in the console
|
||||
// must stop being called without a restart. It is wired here rather than where the
|
||||
// engine is built because the switch belongs to the server, which does not exist yet
|
||||
// at that point.
|
||||
recommender.TracearrAllowed = server.TracearrEnabled
|
||||
dispatcher.SetPaused(server.ActivityPaused)
|
||||
dispatcher.Start(ctx)
|
||||
if creditsService != nil {
|
||||
creditsService.SetPaused(server.ActivityPaused)
|
||||
go creditsService.Run(ctx)
|
||||
runtimestats.Go("Credits detection", "Credits detection", func() { creditsService.Run(ctx) })
|
||||
}
|
||||
if ingester != nil {
|
||||
// Quiet time is honoured here rather than at the hook: the webhook is recorded
|
||||
@@ -313,7 +320,7 @@ func run(log *slog.Logger, events *logging.Buffer, logLevel *slog.LevelVar) erro
|
||||
// is there rather than that it is coming. Installed here for the same reason
|
||||
// SetAfterSync is: library stays ignorant of what an alert is.
|
||||
ingester.Announce = server.AnnounceLibraryIngest
|
||||
go ingester.Run(ctx)
|
||||
runtimestats.Go("Library ingest", "Library sync", func() { ingester.Run(ctx) })
|
||||
}
|
||||
|
||||
// Registration is separate from construction so the task list reads as a declaration
|
||||
@@ -321,6 +328,12 @@ func run(log *slog.Logger, events *logging.Buffer, logLevel *slog.LevelVar) erro
|
||||
server.RegisterHousekeeping(sched)
|
||||
server.RegisterCreditsTasks(sched)
|
||||
server.RegisterWatchTimeTasks(sched)
|
||||
server.RegisterRequestTasks(sched)
|
||||
// Sonarr's daily catalogue reading, Radarr's film refresh, the Tracearr import and the
|
||||
// For You rebuild all used to be goroutines with tickers of their own here. They are
|
||||
// scheduler tasks now, which is what gives the console's integrations area a run
|
||||
// history without a second store — and what lets an operator run any of them by hand.
|
||||
server.RegisterIntegrationTasks(sched)
|
||||
sched.Start(ctx)
|
||||
|
||||
// Installed after the server exists, because both halves of a finished import are
|
||||
@@ -344,62 +357,60 @@ func run(log *slog.Logger, events *logging.Buffer, logLevel *slog.LevelVar) erro
|
||||
if err := server.LoadGatewaySettings(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
go server.WatchGatewaySettings(ctx, 30*time.Second)
|
||||
go server.WatchMaintenance(ctx, 30*time.Second)
|
||||
go server.WatchQuietTime(ctx, 30*time.Second)
|
||||
// Every long-running worker below is started through runtimestats.Go rather than with
|
||||
// a bare `go`, so the admin console can name what is running instead of reporting a
|
||||
// count of goroutines nobody can interpret. The name is the worker's identity across
|
||||
// restarts and appears verbatim in the console, so it is wording rather than a symbol.
|
||||
runtimestats.Go("Gateway settings watcher", "Gateway settings", func() {
|
||||
server.WatchGatewaySettings(ctx, 30*time.Second)
|
||||
})
|
||||
runtimestats.Go("Maintenance watcher", "Gateway settings", func() {
|
||||
server.WatchMaintenance(ctx, 30*time.Second)
|
||||
})
|
||||
runtimestats.Go("Quiet time watcher", "Gateway settings", func() {
|
||||
server.WatchQuietTime(ctx, 30*time.Second)
|
||||
})
|
||||
// One probe per gateway, not per TV: the answer is the same for the whole house.
|
||||
go server.WatchEmbyReachability(ctx)
|
||||
// One Sonarr catalogue reading per day records lifecycle changes for the household and
|
||||
// materialises cancellation notifications for every known viewer.
|
||||
go server.WatchSonarrLifecycle(ctx, 24*time.Hour)
|
||||
runtimestats.Go("Emby health probe", "Emby", func() { server.WatchEmbyReachability(ctx) })
|
||||
// The trend ring behind the console's runtime page. A single instantaneous goroutine
|
||||
// or heap figure cannot show a leak; this is what makes one visible.
|
||||
runtimestats.Go("Runtime sampler", "Gateway API", func() { runtimestats.StartSampling(ctx) })
|
||||
|
||||
if err := server.LoadUpdatePolicy(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
go server.WatchUpdatePolicy(ctx, 60*time.Second)
|
||||
runtimestats.Go("App update policy watcher", "Gateway settings", func() {
|
||||
server.WatchUpdatePolicy(ctx, 60*time.Second)
|
||||
})
|
||||
|
||||
go syncer.Schedule(ctx, server.LibrarySyncInterval, server.ActivityPaused)
|
||||
runtimestats.Go("Library sync schedule", "Library sync", func() {
|
||||
syncer.Schedule(ctx, server.LibrarySyncInterval, server.ActivityPaused)
|
||||
})
|
||||
if cfg.SyncOnStart {
|
||||
go func() {
|
||||
runtimestats.Go("Startup library sync", "Library sync", func() {
|
||||
if server.ActivityPaused() {
|
||||
return
|
||||
}
|
||||
if _, err := syncer.Sync(ctx, "incremental", "startup"); err != nil {
|
||||
log.Warn("startup sync failed", "error", err)
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
if forYouService != nil {
|
||||
go forYouService.Schedule(
|
||||
ctx,
|
||||
cfg.TracearrSyncInterval,
|
||||
cfg.TracearrFullInterval,
|
||||
cfg.ForYouRebuildHour,
|
||||
server.ActivityPaused,
|
||||
)
|
||||
go func() {
|
||||
// The import and the daily rebuild are scheduler tasks now — see
|
||||
// RegisterIntegrationTasks — so what is left here is the one piece of start-up work
|
||||
// neither of them is: profiles produced by an older algorithm. Only a version change
|
||||
// warrants it, and normal dirty profiles still wait for the daily off-peak rebuild.
|
||||
runtimestats.Go("Startup For You migration", "Recommendations", func() {
|
||||
if server.ActivityPaused() {
|
||||
return
|
||||
}
|
||||
importCtx, cancel := context.WithTimeout(ctx, cfg.SyncTimeout)
|
||||
// Only if one is actually owed. An unconditional startup import made every
|
||||
// redeploy or container bounce a fresh pass over Tracearr's history.
|
||||
if _, _, err := forYouService.ImportIfDue(
|
||||
importCtx, cfg.TracearrSyncInterval, cfg.TracearrFullInterval,
|
||||
); err != nil {
|
||||
cancel()
|
||||
log.Warn("startup Tracearr import failed", "error", err)
|
||||
return
|
||||
}
|
||||
cancel()
|
||||
// Only an algorithm-version change warrants startup work. Normal dirty
|
||||
// profiles wait for the daily off-peak rebuild.
|
||||
rebuildCtx, rebuildCancel := context.WithTimeout(ctx, cfg.SyncTimeout)
|
||||
defer rebuildCancel()
|
||||
rebuildCtx, cancel := context.WithTimeout(ctx, cfg.SyncTimeout)
|
||||
defer cancel()
|
||||
if err := forYouService.RebuildOutdated(rebuildCtx); err != nil {
|
||||
log.Warn("startup outdated For You rebuild failed", "error", err)
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
httpServer := &http.Server{
|
||||
Addr: cfg.ListenAddr,
|
||||
@@ -410,7 +421,7 @@ func run(log *slog.Logger, events *logging.Buffer, logLevel *slog.LevelVar) erro
|
||||
}
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
runtimestats.Go("HTTP listener", "HTTP server", func() {
|
||||
log.Info("gateway ready",
|
||||
"listen", cfg.ListenAddr,
|
||||
"emby", cfg.EmbyURL,
|
||||
@@ -423,7 +434,7 @@ func run(log *slog.Logger, events *logging.Buffer, logLevel *slog.LevelVar) erro
|
||||
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
errCh <- err
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
|
||||
Reference in New Issue
Block a user