daemon.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package cli // import "miniflux.app/v2/internal/cli"
  4. import (
  5. "context"
  6. "log/slog"
  7. "net/http"
  8. "os"
  9. "os/signal"
  10. "syscall"
  11. "time"
  12. "miniflux.app/v2/internal/config"
  13. "miniflux.app/v2/internal/http/server"
  14. "miniflux.app/v2/internal/metric"
  15. "miniflux.app/v2/internal/storage"
  16. "miniflux.app/v2/internal/systemd"
  17. "miniflux.app/v2/internal/worker"
  18. )
  19. func startDaemon(store *storage.Storage) {
  20. slog.Debug("Starting daemon...")
  21. stop := make(chan os.Signal, 1)
  22. signal.Notify(stop, os.Interrupt)
  23. signal.Notify(stop, syscall.SIGTERM)
  24. pool := worker.NewPool(store, config.Opts.WorkerPoolSize())
  25. if config.Opts.HasSchedulerService() && !config.Opts.HasMaintenanceMode() {
  26. runScheduler(store, pool)
  27. }
  28. var httpServers []*http.Server
  29. if config.Opts.HasHTTPService() {
  30. httpServers = server.StartWebServer(store, pool)
  31. }
  32. metricsCtx, cancelMetrics := context.WithCancel(context.Background())
  33. if config.Opts.HasMetricsCollector() {
  34. collector := metric.NewCollector(store, config.Opts.MetricsRefreshInterval())
  35. go collector.GatherStorageMetrics(metricsCtx)
  36. }
  37. if systemd.HasNotifySocket() {
  38. slog.Debug("Sending readiness notification to Systemd")
  39. if err := systemd.SdNotify(systemd.SdNotifyReady); err != nil {
  40. slog.Error("Unable to send readiness notification to systemd", slog.Any("error", err))
  41. }
  42. if config.Opts.HasWatchdog() && systemd.HasSystemdWatchdog() {
  43. slog.Debug("Activating Systemd watchdog")
  44. go func() {
  45. interval, err := systemd.WatchdogInterval()
  46. if err != nil {
  47. slog.Error("Unable to get watchdog interval from systemd", slog.Any("error", err))
  48. return
  49. }
  50. for {
  51. if err := store.Ping(); err != nil {
  52. slog.Error("Unable to ping database", slog.Any("error", err))
  53. } else {
  54. systemd.SdNotify(systemd.SdNotifyWatchdog)
  55. }
  56. time.Sleep(interval / 3)
  57. }
  58. }()
  59. }
  60. }
  61. <-stop
  62. slog.Debug("Shutting down the process")
  63. cancelMetrics()
  64. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  65. defer cancel()
  66. if len(httpServers) > 0 {
  67. slog.Debug("Shutting down HTTP servers...")
  68. for _, server := range httpServers {
  69. if server != nil {
  70. if err := server.Shutdown(ctx); err != nil {
  71. slog.Error("HTTP server shutdown error", slog.Any("error", err), slog.String("addr", server.Addr))
  72. }
  73. }
  74. }
  75. slog.Debug("All HTTP servers shut down.")
  76. } else {
  77. slog.Debug("No HTTP servers to shut down.")
  78. }
  79. slog.Debug("Shutting down worker pool...")
  80. pool.Shutdown()
  81. slog.Debug("Worker pool shut down.")
  82. slog.Debug("Process gracefully stopped")
  83. }