You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

131 lines
4.0 KiB

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "net/http"
  6. _ "net/http/pprof"
  7. "os"
  8. "os/signal"
  9. "strings"
  10. "syscall"
  11. "time"
  12. redisprom "github.com/globocom/go-redis-prometheus"
  13. "github.com/go-redis/redis/v8"
  14. "github.com/gorilla/mux"
  15. "github.com/prometheus/client_golang/prometheus/promhttp"
  16. "github.com/tevino/abool/v2"
  17. )
  18. const (
  19. ItemChannelBuffer = 100000
  20. ItemWrapSize = 100000
  21. )
  22. func main() {
  23. log.SetFlags(log.Flags() | log.Lshortfile)
  24. trackerRedisOptions, err := redis.ParseURL(os.Getenv("REDIS_TRACKER"))
  25. if err != nil {
  26. log.Panicf("invalid REDIS_TRACKER url: %s", err)
  27. }
  28. trackerRedisOptions.ReadTimeout = 15 * time.Minute
  29. trackerRedisClient := redis.NewClient(trackerRedisOptions)
  30. backfeedRedisClient := redis.NewClusterClient(&redis.ClusterOptions{
  31. Addrs: strings.Split(os.Getenv("REDIS_BACKFEED_ADDRS"), ","),
  32. Username: os.Getenv("REDIS_BACKFEED_USERNAME"),
  33. Password: os.Getenv("REDIS_BACKFEED_PASSWORD"),
  34. ReadTimeout: 15 * time.Minute,
  35. PoolSize: 256,
  36. })
  37. backfeedRedisMetricsHook := redisprom.NewHook(
  38. redisprom.WithInstanceName("backfeed"),
  39. )
  40. backfeedRedisClient.AddHook(backfeedRedisMetricsHook)
  41. trackerRedisMetricsHook := redisprom.NewHook(
  42. redisprom.WithInstanceName("tracker"),
  43. )
  44. trackerRedisClient.AddHook(trackerRedisMetricsHook)
  45. if err := trackerRedisClient.Ping(context.Background()).Err(); err != nil {
  46. log.Panicf("unable to ping tracker redis: %s", err)
  47. }
  48. if err := backfeedRedisClient.Ping(context.Background()).Err(); err != nil {
  49. log.Panicf("unable to ping backfeed redis: %s", err)
  50. }
  51. err = backfeedRedisClient.ForEachShard(context.Background(), func(ctx context.Context, client *redis.Client) error {
  52. client.ClientGetName(ctx)
  53. return client.Ping(ctx).Err()
  54. })
  55. globalBackfeedManager := &GlobalBackfeedManager{
  56. ActiveFeeds: map[string]*ProjectBackfeedManager{},
  57. ActiveSlugs: map[string]string{},
  58. TrackerRedis: trackerRedisClient,
  59. BackfeedRedis: backfeedRedisClient,
  60. Populated: abool.New(),
  61. }
  62. globalBackfeedManager.Context, globalBackfeedManager.Cancel = context.WithCancel(context.Background())
  63. defer globalBackfeedManager.CancelAllFeeds()
  64. if err := globalBackfeedManager.RefreshFeeds(); err != nil {
  65. log.Panicf("unable to set up backfeed projects: %s", err)
  66. }
  67. r := mux.NewRouter()
  68. r.Methods(http.MethodPost).Path("/legacy/{slug}").HandlerFunc(globalBackfeedManager.HandleLegacy)
  69. r.Methods(http.MethodGet).Path("/ping").HandlerFunc(globalBackfeedManager.HandlePing)
  70. r.Methods(http.MethodGet).Path("/health").HandlerFunc(globalBackfeedManager.HandleHealth)
  71. r.Methods(http.MethodGet).Path("/lastaccessstats").HandlerFunc(globalBackfeedManager.HandleLastAccessStats)
  72. r.Methods(http.MethodGet).Path("/dump/{key}").HandlerFunc(globalBackfeedManager.HandleDump)
  73. rMetrics := mux.NewRouter()
  74. rMetrics.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)
  75. rMetrics.Path("/metrics").Handler(promhttp.Handler())
  76. doneChan := make(chan bool)
  77. serveErrChan := make(chan error)
  78. go func() {
  79. s := &http.Server{
  80. Addr: os.Getenv("HTTP_ADDR"),
  81. IdleTimeout: 1 * time.Hour,
  82. MaxHeaderBytes: 1 * 1024 * 1024,
  83. Handler: r,
  84. }
  85. serveErrChan <- s.ListenAndServe()
  86. }()
  87. metricsErrChan := make(chan error)
  88. go func() {
  89. if os.Getenv("METRICS_ADDR") != "" {
  90. s := &http.Server{
  91. Addr: os.Getenv("METRICS_ADDR"),
  92. IdleTimeout: 1 * time.Hour,
  93. MaxHeaderBytes: 1 * 1024 * 1024,
  94. Handler: rMetrics,
  95. }
  96. metricsErrChan <- s.ListenAndServe()
  97. } else {
  98. <-doneChan
  99. metricsErrChan <- nil
  100. }
  101. }()
  102. log.Printf("backfeed listening on %s", os.Getenv("HTTP_ADDR"))
  103. if os.Getenv("METRICS_ADDR") != "" {
  104. log.Printf("metrics/debug listening on %s", os.Getenv("METRICS_ADDR"))
  105. }
  106. sc := make(chan os.Signal, 1)
  107. signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
  108. ticker := time.NewTicker(1 * time.Second)
  109. for {
  110. select {
  111. case <-sc:
  112. return
  113. case <-ticker.C:
  114. }
  115. if err := globalBackfeedManager.RefreshFeeds(); err != nil {
  116. log.Printf("unable to refresh backfeed projects: %s", err)
  117. }
  118. }
  119. }