Repository: hasura/graphql-engine
File: server/src-lib/Hasura/App.hs (Haskell)

Code before:
  updateThread <- C.forkImmortal "checkForUpdates" logger $ liftIO $
    checkForUpdates loggerCtx _icHttpManager

  -- start a background thread for telemetry
  telemetryThread <- if soEnableTelemetry
    then do
      unLogger logger $ mkGenericStrLog LevelInfo "telemetry" telemetryNotice

      (dbId, pgVersion) <- liftIO $ runTxIO _icPgPool (Q.ReadCommitted, Nothing) $
        (,) <$> getDbId <*> getPgVersion

      telemetryThread <- C.forkImmortal "runTelemetry" logger $ liftIO $
        runTelemetry logger _icHttpManager (getSCFromRef cacheRef) dbId _icInstanceId pgVersion
      return $ Just telemetryThread
    else return Nothing

  -- all the immortal threads are collected so that they can be stopped when gracefully shutting down
  let immortalThreads = [ Just schemaSyncListenerThread
                        , Just schemaSyncProcessorThread
                        , Just updateThread
                        , Just asyncActionsThread
                        , Just eventQueueThread
                        , Just scheduledEventsThread
                        , Just cronEventsThread
                        , telemetryThread
                        ]

  finishTime <- liftIO Clock.getCurrentTime
  let apiInitTime = realToFrac $ Clock.diffUTCTime finishTime initTime
  unLogger logger $
    mkGenericLog LevelInfo "server" $ StartupTimeInfo "starting API server" apiInitTime
  let warpSettings = Warp.setPort soPort
                     . Warp.setHost soHost
                     . Warp.setGracefulShutdownTimeout (Just 30) -- 30s graceful shutdown
                     . Warp.setInstallShutdownHandler (shutdownHandler _icLoggers immortalThreads stopWsServer lockedEventsCtx _icPgPool)
                     $ Warp.defaultSettings
  liftIO $ Warp.runSettings warpSettings app

  where
    -- | prepareEvents is a function to unlock all the events that are
    -- locked and unprocessed, which is called while hasura is started.
    -- Locked and unprocessed events can occur in 2 ways
    -- 1.
    -- Hasura's shutdown was not graceful in which all the fetched
    -- events will remain locked and unprocessed(TODO: clean shutdown)
    -- state.
    -- 2.
    -- There is another hasura instance which is processing events and
    -- it will lock events to process them.
    -- So, unlocking all the locked events might re-deliver an event(due to #2).
    prepareEvents pool (Logger logger) = do

Review comment (suggestion):
```suggestion
  -- all the immortal threads are collected so that they can be stopped when gracefully shutting down
  let immortalThreads = [ schemaSyncListenerThread
                        , schemaSyncProcessorThread
                        , updateThread
                        , asyncActionsThread
                        , eventQueueThread
                        , scheduledEventsThread
                        , cronEventsThread
                        ] <> maybe [] pure telemetryThread
```

Code after:
  updateThread <- C.forkImmortal "checkForUpdates" logger $ liftIO $
    checkForUpdates loggerCtx _icHttpManager

  -- start a background thread for telemetry
  telemetryThread <- if soEnableTelemetry
    then do
      unLogger logger $ mkGenericStrLog LevelInfo "telemetry" telemetryNotice

      (dbId, pgVersion) <- liftIO $ runTxIO _icPgPool (Q.ReadCommitted, Nothing) $
        (,) <$> getDbId <*> getPgVersion

      telemetryThread <- C.forkImmortal "runTelemetry" logger $ liftIO $
        runTelemetry logger _icHttpManager (getSCFromRef cacheRef) dbId _icInstanceId pgVersion
      return $ Just telemetryThread
    else return Nothing

  -- all the immortal threads are collected so that they can be stopped when gracefully shutting down
  let immortalThreads = [ schemaSyncListenerThread
                        , schemaSyncProcessorThread
                        , updateThread
                        , asyncActionsThread
                        , eventQueueThread
                        , scheduledEventsThread
                        , cronEventsThread
                        ] <> maybe [] pure telemetryThread

  finishTime <- liftIO Clock.getCurrentTime
  let apiInitTime = realToFrac $ Clock.diffUTCTime finishTime initTime
  unLogger logger $
    mkGenericLog LevelInfo "server" $ StartupTimeInfo "starting API server" apiInitTime
  let warpSettings = Warp.setPort soPort
                     . Warp.setHost soHost
                     . Warp.setGracefulShutdownTimeout (Just 30) -- 30s graceful shutdown
                     . Warp.setInstallShutdownHandler (shutdownHandler _icLoggers immortalThreads stopWsServer lockedEventsCtx _icPgPool)
                     $ Warp.defaultSettings
  liftIO $ Warp.runSettings warpSettings app

  where
    -- | prepareEvents is a function to unlock all the events that are
    -- locked and unprocessed, which is called while hasura is started.
    -- Locked and unprocessed events can occur in 2 ways
    -- 1.
    -- Hasura's shutdown was not graceful in which all the fetched
    -- events will remain locked and unprocessed(TODO: clean shutdown)
    -- state.
    -- 2.
    -- There is another hasura instance which is processing events and
    -- it will lock events to process them.
    -- So, unlocking all the locked events might re-deliver an event(due to #2).
    prepareEvents pool (Logger logger) = do
      liftIO $ logger $ mkGenericStrLog LevelInfo "event_triggers" "preparing data"