add: use SO_REUSEPORT on platform supporting it
This commit is contained in:
committed by
Steve Chavez
parent
de19b04fe4
commit
c297d051dc
@@ -68,7 +68,9 @@ import PostgREST.Version (docsVersion, prettyVersion)
|
||||
import Control.Monad.Writer
|
||||
import qualified Data.ByteString.Char8 as BS
|
||||
import qualified Data.List as L
|
||||
import Data.Streaming.Network (bindPortTCP)
|
||||
import Data.Streaming.Network (HostPreference,
|
||||
bindPortGenEx,
|
||||
bindPortTCP)
|
||||
import qualified Data.Text as T
|
||||
import qualified Network.HTTP.Types as HTTP
|
||||
import Network.HTTP.Types.Header (hVary, hWarning)
|
||||
@@ -81,7 +83,7 @@ import System.Directory (doesPathExist)
|
||||
|
||||
run :: AppState -> Weak ThreadId -> IO ()
|
||||
run appState mainThreadIdRef = do
|
||||
conf <- AppState.getConfig appState
|
||||
conf@AppConfig{configServerReusePort} <- AppState.getConfig appState
|
||||
|
||||
mainSocketRef <- newIORef Nothing
|
||||
let setMainSocketRef = atomicWriteIORef mainSocketRef . Just
|
||||
@@ -101,7 +103,10 @@ run appState mainThreadIdRef = do
|
||||
-- Kick off and wait for the initial SchemaCache load before creating the
|
||||
-- main API socket.
|
||||
AppState.schemaCacheLoader appState
|
||||
AppState.waitForSchemaCacheInit appState
|
||||
if configServerReusePort then
|
||||
AppState.waitForSchemaCacheLoaded appState
|
||||
else
|
||||
AppState.waitForSchemaCacheInit appState
|
||||
|
||||
bracket (initServerSocket conf) NS.close $ \mainSocket -> do
|
||||
|
||||
@@ -296,11 +301,11 @@ addRetryHint delay response = do
|
||||
isServiceUnavailable :: Wai.Response -> Bool
|
||||
isServiceUnavailable response = Wai.responseStatus response == HTTP.status503
|
||||
|
||||
initSocket :: (Applicative f, Traversable f) => Maybe String -> FileMode -> Text -> f Int -> IO (f NS.Socket)
|
||||
initSocket unixSocket unixSocketMode tcpHost tcpPort =
|
||||
initSocket :: (Applicative f, Traversable f) => Maybe String -> FileMode -> Text -> f Int -> (Int -> HostPreference -> IO NS.Socket) -> IO (f NS.Socket)
|
||||
initSocket unixSocket unixSocketMode tcpHost tcpPort bindTCP =
|
||||
maybe initTCPSocket initDomainSocket unixSocket
|
||||
where
|
||||
initTCPSocket = traverse (`bindPortTCP` (fromString $ T.unpack tcpHost)) tcpPort
|
||||
initTCPSocket = traverse (`bindTCP` (fromString $ T.unpack tcpHost)) tcpPort
|
||||
-- I'm not using `streaming-commons`' bindPath function here because it's not defined for Windows,
|
||||
-- but we need to have runtime error if we try to use it in Windows, not compile time error
|
||||
initDomainSocket = fmap pure . (`createAndBindDomainSocket` unixSocketMode)
|
||||
@@ -310,12 +315,20 @@ initServerSocket AppConfig{..} =
|
||||
runIdentity <$> initSocket
|
||||
configServerUnixSocket configServerUnixSocketMode
|
||||
configServerHost (pure configServerPort)
|
||||
(if configServerReusePort then bindPortTCPWithReusePort else bindPortTCP)
|
||||
|
||||
initAdminServerSocket :: AppConfig -> IO (Maybe NS.Socket)
|
||||
initAdminServerSocket AppConfig{..} =
|
||||
initSocket
|
||||
configAdminServerUnixSocket configAdminServerUnixSocketMode
|
||||
configAdminServerHost configAdminServerPort
|
||||
bindPortTCP
|
||||
|
||||
bindPortTCPWithReusePort :: Int -> HostPreference -> IO NS.Socket
|
||||
bindPortTCPWithReusePort port hostPreference =
|
||||
bindPortGenEx [(NS.ReusePort, 1)] NS.Stream port hostPreference >>= listenSocket
|
||||
where
|
||||
listenSocket sock = NS.listen sock (max 2048 NS.maxListenQueue) $> sock
|
||||
|
||||
checkMainAppLive :: IO (Maybe NS.Socket) -> Weak ThreadId -> IO Bool
|
||||
checkMainAppLive getMainSocket mainThreadIdRef =
|
||||
|
||||
@@ -26,6 +26,7 @@ module PostgREST.AppState
|
||||
, isLoaded
|
||||
, isPending
|
||||
, waitForSchemaCacheInit
|
||||
, waitForSchemaCacheLoaded
|
||||
) where
|
||||
|
||||
import qualified Data.ByteString.Char8 as BS
|
||||
@@ -387,6 +388,9 @@ isSchemaCacheLoaded = atomically . (pure . fromMaybe False <=< tryReadTMVar) . g
|
||||
waitForSchemaCacheInit :: AppState -> IO ()
|
||||
waitForSchemaCacheInit = atomically . void . readTMVar . getSCStatusTMVar . stateSCacheStatus
|
||||
|
||||
waitForSchemaCacheLoaded :: AppState -> IO ()
|
||||
waitForSchemaCacheLoaded = atomically . (check <=< readTMVar) . getSCStatusTMVar . stateSCacheStatus
|
||||
|
||||
-- | Reads the in-db config and reads the config file again
|
||||
-- | We don't retry reading the in-db config after it fails immediately, because it could have user errors. We just report the error and continue.
|
||||
readInDbConfig :: Bool -> AppState -> IO ()
|
||||
|
||||
@@ -117,6 +117,7 @@ data AppConfig = AppConfig
|
||||
, configServerCorsAllowedOrigins :: [Text]
|
||||
, configServerHost :: Text
|
||||
, configServerPort :: Int
|
||||
, configServerReusePort :: Bool
|
||||
, configServerTraceHeader :: Maybe (CI.CI BS.ByteString)
|
||||
, configServerTimingEnabled :: Bool
|
||||
, configServerUnixSocket :: Maybe FilePath
|
||||
@@ -204,6 +205,7 @@ toText conf =
|
||||
,("server-cors-allowed-origins", q . T.intercalate "," . configServerCorsAllowedOrigins)
|
||||
,("server-host", q . configServerHost)
|
||||
,("server-port", show . configServerPort)
|
||||
,("server-reuseport", T.toLower . show . configServerReusePort)
|
||||
,("server-trace-header", q . T.decodeUtf8 . maybe mempty CI.original . configServerTraceHeader)
|
||||
,("server-timing-enabled", T.toLower . show . configServerTimingEnabled)
|
||||
,("server-unix-socket", q . maybe mempty T.pack . configServerUnixSocket)
|
||||
@@ -323,6 +325,7 @@ parser optPath env dbSettings roleSettings roleIsolationLvl =
|
||||
<*> parseCORSAllowedOrigins "server-cors-allowed-origins"
|
||||
<*> (defaultServerHost <$> optString "server-host")
|
||||
<*> parseServerPort "server-port"
|
||||
<*> (fromMaybe False <$> optBool "server-reuseport")
|
||||
<*> (fmap (CI.mk . encodeUtf8) <$> optString "server-trace-header")
|
||||
<*> (fromMaybe False <$> optBool "server-timing-enabled")
|
||||
<*> (fmap T.unpack <$> optString "server-unix-socket")
|
||||
@@ -787,6 +790,7 @@ exampleConfigFile = S.unlines
|
||||
, ""
|
||||
, "server-host = \"!4\""
|
||||
, "server-port = 3000"
|
||||
, "server-reuseport = false"
|
||||
, ""
|
||||
, "## Allow getting the request-response timing information through the `Server-Timing` header"
|
||||
, "server-timing-enabled = false"
|
||||
|
||||
Reference in New Issue
Block a user