1515from requests .adapters import HTTPAdapter , Response , CaseInsensitiveDict
1616from typing import TypeVar , Type , List , Optional , Dict , Any , Union
1717from requests .exceptions import HTTPError
18+ from requests .packages .urllib3 .connection import HTTPConnection
1819from requests .packages .urllib3 .poolmanager import PoolManager
1920from requests .packages .urllib3 .util .ssl_ import create_urllib3_context
2021from requests .packages .urllib3 .util import Retry
2425import os
2526import random
2627import requests
28+ import socket
29+ import sys
2730
2831
2932T = TypeVar ("T" )
4750 "DHE-RSA-AES256-GCM-SHA384"
4851)
4952
53+ SOCKET_KEEP_ALIVE = (
54+ socket .SOL_SOCKET ,
55+ socket .SO_KEEPALIVE ,
56+ 1 ,
57+ ) # Enable keep alive.
58+ SOCKET_KEEP_INTVL = (
59+ socket .SOL_TCP ,
60+ socket .TCP_KEEPINTVL ,
61+ 120 ,
62+ ) # Interval of 120s between individual keepalive probes.
63+ KEEP_ALIVE_SOCKET_OPTIONS = [SOCKET_KEEP_ALIVE , SOCKET_KEEP_INTVL ]
64+ if sys .platform != "darwin" :
65+ SOCKET_KEEP_IDLE = (
66+ socket .SOL_TCP ,
67+ socket .TCP_KEEPIDLE ,
68+ 120 ,
69+ ) # After 120s of idle connection, start keepalive probes.
70+ KEEP_ALIVE_SOCKET_OPTIONS .append (SOCKET_KEEP_IDLE )
5071
5172TRACE_ID_HEADER : str = "X-B3-TraceId"
5273TRACE_ID_RANDOM_BYTES = 8
@@ -164,6 +185,7 @@ def create(
164185 user_agent : str ,
165186 service_config : ServiceConfiguration ,
166187 return_none_for_unknown_union_types : bool = False ,
188+ enable_keep_alive : bool = False ,
167189 ) -> T :
168190 # setup retry to match java remoting
169191 # https://github.com/palantir/http-remoting/tree/3.12.0#quality-of-service-retry-failover-throttling
@@ -173,7 +195,9 @@ def create(
173195 status_forcelist = [308 , 429 , 503 ],
174196 backoff_factor = float (service_config .backoff_slot_size ) / 1000 ,
175197 )
176- transport_adapter = TransportAdapter (max_retries = retry )
198+ transport_adapter = TransportAdapter (
199+ max_retries = retry , enable_keep_alive = enable_keep_alive
200+ )
177201 # create a session, for shared connection polling, user agent, etc
178202 session = requests .Session ()
179203 session .headers = CaseInsensitiveDict ({"User-Agent" : user_agent })
@@ -196,18 +220,29 @@ def create(
196220class TransportAdapter (HTTPAdapter ):
197221 """Transport adapter that allows customising ssl things"""
198222
223+ __attrs__ = HTTPAdapter .__attrs__ + ["_enable_keep_alive" ]
224+
225+ def __init__ (self , * args , enable_keep_alive : bool = False , ** kwargs ):
226+ self ._enable_keep_alive = enable_keep_alive
227+ super ().__init__ (* args , ** kwargs )
228+
199229 def init_poolmanager (
200230 self , connections , maxsize , block = False , ** pool_kwargs
201231 ):
202232 self ._pool_connections = connections
203233 self ._pool_maxsize = maxsize
204234 self ._pool_block = block
205235 ssl_context = create_urllib3_context (ciphers = CIPHERS )
236+ keep_alive_pool_kwargs = {
237+ "socket_options" : HTTPConnection .default_socket_options
238+ + KEEP_ALIVE_SOCKET_OPTIONS
239+ }
240+ if self ._enable_keep_alive :
241+ pool_kwargs = {** pool_kwargs , ** keep_alive_pool_kwargs }
206242 self .poolmanager = PoolManager (
207243 num_pools = connections ,
208244 maxsize = maxsize ,
209245 block = block ,
210- strict = True ,
211246 ssl_context = ssl_context ,
212247 ** pool_kwargs
213248 )
0 commit comments