@@ -48,10 +48,22 @@ def _get_razorpay_client() -> razorpay.Client:
4848
4949 _razorpay_client = razorpay .Client (auth = (key_id , key_secret ))
5050
51- # Configure timeout on the underlying requests session
52- # This prevents hanging requests when Razorpay API is slow
53- # (connect timeout: 5s, read timeout: 15s)
54- _razorpay_client .session .timeout = (5 , 15 )
51+ # requests.Session doesn't have a built-in timeout attribute.
52+ # We must use a custom HTTPAdapter to enforce timeouts on all requests.
53+ from requests .adapters import HTTPAdapter
54+
55+ class TimeoutAdapter (HTTPAdapter ):
56+ def __init__ (self , timeout = (5 , 15 ), ** kwargs ):
57+ self .timeout = timeout
58+ super ().__init__ (** kwargs )
59+
60+ def send (self , request , ** kwargs ):
61+ kwargs .setdefault ('timeout' , self .timeout )
62+ return super ().send (request , ** kwargs )
63+
64+ adapter = TimeoutAdapter (timeout = (5 , 15 )) # connect: 5s, read: 15s
65+ _razorpay_client .session .mount ('https://' , adapter )
66+ _razorpay_client .session .mount ('http://' , adapter )
5567
5668 return _razorpay_client
5769
@@ -104,7 +116,9 @@ def create_razorpay_order(
104116 }
105117
106118 # Retry logic for transient network issues
107- max_retries = 2
119+ # With (5s connect + 15s read) timeout and 1 retry, worst case = ~21s + 1s + ~21s = ~43s
120+ # But in practice, timeouts fire much sooner. Keeps us under gunicorn's 30s for most cases.
121+ max_retries = 1
108122 last_error = None
109123
110124 for attempt in range (max_retries + 1 ):
0 commit comments