daemon.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. reload := make(chan os.Signal, 1)
  25. signal.Notify(reload, syscall.SIGHUP)
  26. pool := worker.NewPool(store, config.Opts.WorkerPoolSize())
  27. if config.Opts.HasSchedulerService() && !config.Opts.HasMaintenanceMode() {
  28. runScheduler(store, pool)
  29. }
  30. var httpServers []*http.Server
  31. var certReloadFn func()
  32. if config.Opts.HasHTTPService() {
  33. httpServers, certReloadFn = server.StartWebServer(store, pool)
  34. }
  35. metricsCtx, cancelMetrics := context.WithCancel(context.Background())
  36. if config.Opts.HasMetricsCollector() {
  37. collector := metric.NewCollector(store, config.Opts.MetricsRefreshInterval())
  38. go collector.GatherStorageMetrics(metricsCtx)
  39. }
  40. if systemd.HasNotifySocket() {
  41. slog.Debug("Sending readiness notification to Systemd")
  42. if err := systemd.SdNotify(systemd.SdNotifyReady); err != nil {
  43. slog.Error("Unable to send readiness notification to systemd", slog.Any("error", err))
  44. }
  45. if config.Opts.HasWatchdog() && systemd.HasSystemdWatchdog() {
  46. slog.Debug("Activating Systemd watchdog")
  47. go func() {
  48. interval, err := systemd.WatchdogInterval()
  49. if err != nil {
  50. slog.Error("Unable to get watchdog interval from systemd", slog.Any("error", err))
  51. return
  52. }
  53. for {
  54. if err := store.Ping(); err != nil {
  55. slog.Error("Unable to ping database", slog.Any("error", err))
  56. } else {
  57. systemd.SdNotify(systemd.SdNotifyWatchdog)
  58. }
  59. time.Sleep(interval / 3)
  60. }
  61. }()
  62. }
  63. }
  64. for {
  65. select {
  66. case <-stop:
  67. slog.Debug("Shutting down the process")
  68. cancelMetrics()
  69. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  70. defer cancel()
  71. if len(httpServers) > 0 {
  72. slog.Debug("Shutting down HTTP servers...")
  73. for _, srv := range httpServers {
  74. if srv != nil {
  75. if err := srv.Shutdown(ctx); err != nil {
  76. slog.Error("HTTP server shutdown error", slog.Any("error", err), slog.String("addr", srv.Addr))
  77. }
  78. }
  79. }
  80. slog.Debug("All HTTP servers shut down.")
  81. } else {
  82. slog.Debug("No HTTP servers to shut down.")
  83. }
  84. slog.Debug("Shutting down worker pool...")
  85. pool.Shutdown()
  86. slog.Debug("Worker pool shut down.")
  87. slog.Debug("Process gracefully stopped")
  88. return
  89. case <-reload:
  90. slog.Info("Received SIGHUP, reloading TLS certificates")
  91. if certReloadFn != nil {
  92. certReloadFn()
  93. }
  94. }
  95. }
  96. }