youssefreda9 commited on
Commit
75e46c4
·
1 Parent(s): a52b4fe

fix: Grammar Gradio client retry with exponential backoff (3 attempts, 2s/4s/8s)

Browse files
Files changed (1) hide show
  1. src/nlp/grammar/grammar_service.py +35 -5
src/nlp/grammar/grammar_service.py CHANGED
@@ -70,6 +70,9 @@ def get_grammar_model():
70
 
71
  Transient errors (rate limiting, network timeouts) are NOT cached —
72
  the next request will retry loading. Only permanent failures are cached.
 
 
 
73
  """
74
  global _grammar_checker, _load_error
75
 
@@ -83,11 +86,37 @@ def get_grammar_model():
83
  t0 = time.time()
84
  logger.info("Loading Grammar model (lazy init)...")
85
 
86
- # 1. Initialize Gradio Client
87
- logger.info(f"Connecting to Gradio Space: {GRADIO_SPACE}")
88
  from gradio_client import Client
89
- client = Client(GRADIO_SPACE)
90
- logger.info("Gradio Client connected")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  # 2. Initialize rule-based post-processor (camel-tools)
93
  logger.info("Loading ArabicGrammarGuard (camel-tools MLE disambiguator)...")
@@ -111,7 +140,8 @@ def get_grammar_model():
111
  # Transient errors (rate limiting, network) should NOT be cached —
112
  # allow retry on next request
113
  transient_keywords = ['Too many requests', 'rate limit', 'timeout',
114
- 'ConnectionError', 'ConnectTimeout', 'ReadTimeout']
 
115
  is_transient = any(kw.lower() in error_msg.lower() for kw in transient_keywords)
116
 
117
  if is_transient:
 
70
 
71
  Transient errors (rate limiting, network timeouts) are NOT cached —
72
  the next request will retry loading. Only permanent failures are cached.
73
+
74
+ The Gradio Client connection retries up to 3 times with exponential backoff
75
+ to handle sleeping Spaces and rate-limit responses.
76
  """
77
  global _grammar_checker, _load_error
78
 
 
86
  t0 = time.time()
87
  logger.info("Loading Grammar model (lazy init)...")
88
 
89
+ # 1. Initialize Gradio Client — with retry for rate limiting / sleeping Spaces
 
90
  from gradio_client import Client
91
+ client = None
92
+ max_retries = 3
93
+ last_err = None
94
+
95
+ for attempt in range(1, max_retries + 1):
96
+ try:
97
+ logger.info(f"Connecting to Gradio Space: {GRADIO_SPACE} (attempt {attempt}/{max_retries})")
98
+ client = Client(GRADIO_SPACE)
99
+ logger.info("Gradio Client connected")
100
+ break
101
+ except Exception as conn_err:
102
+ last_err = conn_err
103
+ err_msg = str(conn_err).lower()
104
+ is_retryable = any(kw in err_msg for kw in [
105
+ 'too many requests', 'rate limit', '429',
106
+ 'timeout', 'connection', 'sleeping'
107
+ ])
108
+ if is_retryable and attempt < max_retries:
109
+ wait = 2 ** attempt # 2s, 4s, 8s
110
+ logger.warning(
111
+ f"Gradio connection attempt {attempt} failed ({conn_err}). "
112
+ f"Retrying in {wait}s..."
113
+ )
114
+ time.sleep(wait)
115
+ else:
116
+ raise # Not retryable or last attempt — bubble up
117
+
118
+ if client is None:
119
+ raise RuntimeError(f"Gradio connection failed after {max_retries} attempts: {last_err}")
120
 
121
  # 2. Initialize rule-based post-processor (camel-tools)
122
  logger.info("Loading ArabicGrammarGuard (camel-tools MLE disambiguator)...")
 
140
  # Transient errors (rate limiting, network) should NOT be cached —
141
  # allow retry on next request
142
  transient_keywords = ['Too many requests', 'rate limit', 'timeout',
143
+ 'ConnectionError', 'ConnectTimeout', 'ReadTimeout',
144
+ '429', 'sleeping']
145
  is_transient = any(kw.lower() in error_msg.lower() for kw in transient_keywords)
146
 
147
  if is_transient: