@@ -72,7 +72,8 @@ import PostgREST.SchemaCache (SchemaCache (..),
7272import PostgREST.SchemaCache.Identifiers (quoteQi )
7373import PostgREST.Unix (createAndBindDomainSocket )
7474
75- import Data.Streaming.Network (bindPortTCP , bindRandomPortTCP )
75+ import Data.Streaming.Network (HostPreference , bindPortGenEx ,
76+ bindPortTCP , bindRandomPortTCP )
7677import Data.String (IsString (.. ))
7778import Protolude
7879
@@ -184,7 +185,7 @@ initSockets AppConfig{..} = do
184185 (_, sock) <-
185186 if cfg'port /= 0
186187 then do
187- sock <- bindPortTCP cfg'port (fromString $ T. unpack cfg'host)
188+ sock <- bindPortTCPWithReusePort cfg'port (fromString $ T. unpack cfg'host)
188189 pure (cfg'port, sock)
189190 else do
190191 -- explicitly bind to a random port, returning bound port number
@@ -194,12 +195,25 @@ initSockets AppConfig{..} = do
194195
195196 adminSock <- case cfg'adminPort of
196197 Just adminPort -> do
197- adminSock <- bindPortTCP adminPort (fromString $ T. unpack cfg'adminHost)
198+ adminSock <- bindPortTCPWithReusePort adminPort (fromString $ T. unpack cfg'adminHost)
198199 pure $ Just adminSock
199200 Nothing -> pure Nothing
200201
201202 pure (sock, adminSock)
202203
204+ bindPortTCPWithReusePort :: Int -> HostPreference -> IO NS. Socket
205+ bindPortTCPWithReusePort port hostPreference
206+ = do
207+ -- Some unix variants can expose ReusePort but reject it at runtime.
208+ -- Fall back to the default behavior when that happens.
209+ socketWithReusePort <- try (bindPortGenEx reusePortOpts NS. Stream port hostPreference) :: IO (Either SomeException NS. Socket )
210+ either (const $ bindPortTCP port hostPreference) listenSocket socketWithReusePort
211+ where
212+ reusePortOpts = [(NS. ReusePort , 1 )]
213+ listenSocket sock = do
214+ NS. listen sock (max 2048 NS. maxListenQueue)
215+ pure sock
216+
203217initPool :: AppConfig -> ObservationHandler -> IO SQL. Pool
204218initPool AppConfig {.. } observer = do
205219 SQL. acquire $ SQL. settings
0 commit comments