Skip to content

Commit 070d7a1

Browse files
committed
add: use SO_REUSEPORT on platform supporting it
1 parent 4604c09 commit 070d7a1

3 files changed

Lines changed: 17 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file. From versio
1313
- Optimize requests with `Prefer: count=exact` that do not use ranges or `db-max-rows` by @laurenceisla in #3957
1414
+ Removed unnecessary double count when building the `Content-Range`.
1515
- Add config `client_error_verbosity` to customize error verbosity by @taimoorzaeem in #4088, #3980, #3824
16+
- Use SO_REUSEPORT on platforms supporting it by @mkleczek in #4703 #4694
1617

1718
### Changed
1819

src/PostgREST/App.hs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ import PostgREST.Version (docsVersion, prettyVersion)
6363

6464
import qualified Data.ByteString.Char8 as BS
6565
import qualified Data.List as L
66-
import Data.Streaming.Network (bindPortTCP,
66+
import Data.Streaming.Network (HostPreference,
67+
bindPortGenEx, bindPortTCP,
6768
bindRandomPortTCP)
6869
import qualified Data.Text as T
6970
import qualified Network.HTTP.Types as HTTP
@@ -260,7 +261,7 @@ initSockets AppConfig{..} = do
260261
(_, sock) <-
261262
if cfg'port /= 0
262263
then do
263-
sock <- bindPortTCP cfg'port (fromString $ T.unpack cfg'host)
264+
sock <- bindPortTCPWithReusePort cfg'port (fromString $ T.unpack cfg'host)
264265
pure (cfg'port, sock)
265266
else do
266267
-- explicitly bind to a random port, returning bound port number
@@ -270,9 +271,21 @@ initSockets AppConfig{..} = do
270271

271272
adminSock <- case cfg'adminPort of
272273
Just adminPort -> do
273-
adminSock <- bindPortTCP adminPort (fromString $ T.unpack cfg'adminHost)
274+
adminSock <- bindPortTCPWithReusePort adminPort (fromString $ T.unpack cfg'adminHost)
274275
pure $ Just adminSock
275276
Nothing -> pure Nothing
276277

277278
pure (sock, adminSock)
278279

280+
bindPortTCPWithReusePort :: Int -> HostPreference -> IO NS.Socket
281+
bindPortTCPWithReusePort port hostPreference
282+
= do
283+
-- Some unix variants can expose ReusePort but reject it at runtime.
284+
-- Fall back to the default behavior when that happens.
285+
socketWithReusePort <- try (bindPortGenEx reusePortOpts NS.Stream port hostPreference) :: IO (Either SomeException NS.Socket)
286+
either (const $ bindPortTCP port hostPreference) listenSocket socketWithReusePort
287+
where
288+
reusePortOpts = [(NS.ReusePort, 1)]
289+
listenSocket sock = do
290+
NS.listen sock (max 2048 NS.maxListenQueue)
291+
pure sock

test/io/test_io.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ def test_random_port_bound(defaultenv):
133133
assert True # liveness check is done by run(), so we just need to check that it doesn't fail
134134

135135

136-
@pytest.mark.xfail(reason="SO_REUSEPORT handover is currently failing")
137136
def test_so_reuseport_zero_downtime_handover(defaultenv):
138137
"A second PostgREST instance should take over on the same main/admin ports without request failures."
139138

0 commit comments

Comments
 (0)