DrValera commited on
Commit
9e6e0eb
·
verified ·
1 Parent(s): f7c87cb

Adjusting self ping for datfid master for not to sleep

Browse files
Files changed (1) hide show
  1. main.py +48 -27
main.py CHANGED
@@ -11,6 +11,8 @@ UPSTREAM_URL = os.environ.get("hf_url", "").rstrip("/") # url to acc
11
  HF_TOKEN = os.environ.get("hf_token") # HF access token to access Private Space
12
  DEMO_FORWARD_URL = os.getenv("DEMO_FORWARD_URL", "").rstrip("/") # url to acces demo space
13
  DATFID_DEMO_TOKEN = os.getenv("DATFID_DEMO_TOKEN", "") # token to access demo space
 
 
14
 
15
  if not HF_TOKEN:
16
  raise RuntimeError("Missing secret 'hf_token' in public Space.")
@@ -39,8 +41,9 @@ SDK_MAX_BODY_BYTES_extended = int(os.getenv("SDK_MAX_BODY_BYTES_extended", "1250
39
 
40
  # How long to wait for upstream (API) response; long runs may need 30+ min (1800+)
41
  UPSTREAM_TIMEOUT = float(os.getenv("UPSTREAM_TIMEOUT", "900")) # 15 minutes
42
- # While waiting for a response, ping upstream every N seconds so the backend Space does not sleep
43
  PING_UPSTREAM_INTERVAL = float(os.getenv("PING_UPSTREAM_INTERVAL", "270"))
 
44
 
45
  # Early global body-size guard (runs before routes)
46
  @app.middleware("http")
@@ -79,25 +82,31 @@ def _filter_resp_headers(headers: dict) -> dict:
79
  allowed = {"content-disposition"}
80
  return {k: v for k, v in headers.items() if k.lower() in allowed}
81
 
82
- async def _ping_upstream_loop(ping_url: str, headers: dict, interval: float):
83
- """Background task: every `interval` seconds, GET ping_url to keep the backend Space awake. Stops when cancelled."""
84
  if interval <= 0:
85
  return
86
  while True:
87
  await asyncio.sleep(interval)
88
  try:
89
  async with httpx.AsyncClient(timeout=10.0) as client:
 
 
 
 
 
90
  await client.get(ping_url, headers=headers)
91
  except asyncio.CancelledError:
92
  break
93
  except Exception:
94
- pass # ignore ping errors
95
 
96
- def _start_ping_task(ping_url: str, headers: dict):
97
- """Start a background task that pings the given URL every PING_UPSTREAM_INTERVAL seconds. Returns the task (or None); cancel it when the main request finishes."""
98
- if PING_UPSTREAM_INTERVAL <= 0:
 
99
  return None
100
- return asyncio.create_task(_ping_upstream_loop(ping_url, headers, PING_UPSTREAM_INTERVAL))
101
 
102
  async def _cancel_ping_task(task: asyncio.Task | None):
103
  if task is None:
@@ -133,8 +142,8 @@ async def _forward(path: str, method: str = "GET", json_body=None, user_token: s
133
  if user_token:
134
  headers["X-API-Key"] = user_token
135
 
136
- # While waiting for upstream, call backend secure_ping every PING_UPSTREAM_INTERVAL seconds
137
- ping_url = f"{UPSTREAM_URL}secure-ping/"
138
  ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
139
  if user_token:
140
  ping_headers["X-API-Key"] = user_token
@@ -149,12 +158,13 @@ async def _forward(path: str, method: str = "GET", json_body=None, user_token: s
149
 
150
  request_task = asyncio.create_task(do_request())
151
  interval = PING_UPSTREAM_INTERVAL if PING_UPSTREAM_INTERVAL > 0 else 0.0
 
152
  try:
153
  while not request_task.done():
154
- if interval <= 0:
155
  await request_task
156
  break
157
- ping_sleep = asyncio.create_task(asyncio.sleep(interval))
158
  done, pending = await asyncio.wait(
159
  {request_task, ping_sleep},
160
  return_when=asyncio.FIRST_COMPLETED,
@@ -169,11 +179,16 @@ async def _forward(path: str, method: str = "GET", json_body=None, user_token: s
169
  pass
170
  if request_task in done:
171
  break
172
- try:
173
- async with httpx.AsyncClient(timeout=10.0) as client:
174
- await client.get(ping_url, headers=ping_headers)
175
- except Exception:
176
- pass
 
 
 
 
 
177
  if not request_task.done():
178
  request_task.cancel()
179
  try:
@@ -216,7 +231,7 @@ async def _forward_stream(path: str, files=None, data=None, user_token: str | No
216
  ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
217
  if user_token:
218
  ping_headers["X-API-Key"] = user_token
219
- ping_task = _start_ping_task(f"{UPSTREAM_URL}secure-ping/", ping_headers)
220
  timeout = httpx.Timeout(UPSTREAM_TIMEOUT)
221
  client = httpx.AsyncClient(timeout=timeout, follow_redirects=True)
222
 
@@ -280,7 +295,7 @@ async def _forward_stream(path: str, files=None, data=None, user_token: str | No
280
 
281
 
282
  async def _forward_multipart_json(path: str, files=None, data=None, user_token: str | None = None, method: str = "POST"):
283
- """POST multipart to upstream and return JSON. Sends secure_ping every PING_UPSTREAM_INTERVAL while waiting."""
284
  url = f"{UPSTREAM_URL}{path}"
285
  headers = {
286
  "Authorization": f"Bearer {HF_TOKEN}",
@@ -288,7 +303,7 @@ async def _forward_multipart_json(path: str, files=None, data=None, user_token:
288
  }
289
  if user_token:
290
  headers["X-API-Key"] = user_token
291
- ping_url = f"{UPSTREAM_URL}secure-ping/"
292
  ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
293
  if user_token:
294
  ping_headers["X-API-Key"] = user_token
@@ -302,12 +317,13 @@ async def _forward_multipart_json(path: str, files=None, data=None, user_token:
302
 
303
  request_task = asyncio.create_task(do_request())
304
  interval = PING_UPSTREAM_INTERVAL if PING_UPSTREAM_INTERVAL > 0 else 0.0
 
305
  try:
306
  while not request_task.done():
307
- if interval <= 0:
308
  await request_task
309
  break
310
- ping_sleep = asyncio.create_task(asyncio.sleep(interval))
311
  done, pending = await asyncio.wait(
312
  {request_task, ping_sleep},
313
  return_when=asyncio.FIRST_COMPLETED,
@@ -322,11 +338,16 @@ async def _forward_multipart_json(path: str, files=None, data=None, user_token:
322
  pass
323
  if request_task in done:
324
  break
325
- try:
326
- async with httpx.AsyncClient(timeout=10.0) as client:
327
- await client.get(ping_url, headers=ping_headers)
328
- except Exception:
329
- pass
 
 
 
 
 
330
  if not request_task.done():
331
  request_task.cancel()
332
  try:
 
11
  HF_TOKEN = os.environ.get("hf_token") # HF access token to access Private Space
12
  DEMO_FORWARD_URL = os.getenv("DEMO_FORWARD_URL", "").rstrip("/") # url to acces demo space
13
  DATFID_DEMO_TOKEN = os.getenv("DATFID_DEMO_TOKEN", "") # token to access demo space
14
+ # This Space's public URL (used to ping self while waiting so HF does not put this Space to sleep). Override with SELF_URL env if different.
15
+ SELF_URL = os.getenv("SELF_URL", "https://datfid-org-datfid-master.hf.space").rstrip("/")
16
 
17
  if not HF_TOKEN:
18
  raise RuntimeError("Missing secret 'hf_token' in public Space.")
 
41
 
42
  # How long to wait for upstream (API) response; long runs may need 30+ min (1800+)
43
  UPSTREAM_TIMEOUT = float(os.getenv("UPSTREAM_TIMEOUT", "900")) # 15 minutes
44
+ # While waiting for a response: send secure_ping to upstream every N seconds; if SELF_URL set, also ping self every SELF_PING_INTERVAL so this Space stays awake
45
  PING_UPSTREAM_INTERVAL = float(os.getenv("PING_UPSTREAM_INTERVAL", "270"))
46
+ SELF_PING_INTERVAL = float(os.getenv("SELF_PING_INTERVAL", "120"))
47
 
48
  # Early global body-size guard (runs before routes)
49
  @app.middleware("http")
 
82
  allowed = {"content-disposition"}
83
  return {k: v for k, v in headers.items() if k.lower() in allowed}
84
 
85
+ async def _ping_upstream_loop(ping_url: str, headers: dict, interval: float, self_url: str = ""):
86
+ """Every `interval` seconds: if self_url set, GET self_url/keep-alive (keep this Space awake), then GET ping_url (backend). Stops when cancelled."""
87
  if interval <= 0:
88
  return
89
  while True:
90
  await asyncio.sleep(interval)
91
  try:
92
  async with httpx.AsyncClient(timeout=10.0) as client:
93
+ if self_url:
94
+ try:
95
+ await client.get(f"{self_url}/keep-alive")
96
+ except Exception:
97
+ pass
98
  await client.get(ping_url, headers=headers)
99
  except asyncio.CancelledError:
100
  break
101
  except Exception:
102
+ pass
103
 
104
+ def _start_ping_task(ping_url: str, headers: dict, self_url: str = ""):
105
+ """Start background ping task. If SELF_URL set, uses SELF_PING_INTERVAL and pings self + backend; else PING_UPSTREAM_INTERVAL, backend only."""
106
+ interval = (SELF_PING_INTERVAL if self_url and SELF_PING_INTERVAL > 0 else PING_UPSTREAM_INTERVAL) or PING_UPSTREAM_INTERVAL
107
+ if interval <= 0:
108
  return None
109
+ return asyncio.create_task(_ping_upstream_loop(ping_url, headers, interval, self_url))
110
 
111
  async def _cancel_ping_task(task: asyncio.Task | None):
112
  if task is None:
 
142
  if user_token:
143
  headers["X-API-Key"] = user_token
144
 
145
+ # While waiting: ping backend (secure_ping) and, if SELF_URL set, ping self so this Space stays awake
146
+ ping_url = f"{UPSTREAM_URL}/secure-ping/"
147
  ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
148
  if user_token:
149
  ping_headers["X-API-Key"] = user_token
 
158
 
159
  request_task = asyncio.create_task(do_request())
160
  interval = PING_UPSTREAM_INTERVAL if PING_UPSTREAM_INTERVAL > 0 else 0.0
161
+ wait_sec = (SELF_PING_INTERVAL if SELF_URL and SELF_PING_INTERVAL > 0 else interval) or interval
162
  try:
163
  while not request_task.done():
164
+ if wait_sec <= 0:
165
  await request_task
166
  break
167
+ ping_sleep = asyncio.create_task(asyncio.sleep(wait_sec))
168
  done, pending = await asyncio.wait(
169
  {request_task, ping_sleep},
170
  return_when=asyncio.FIRST_COMPLETED,
 
179
  pass
180
  if request_task in done:
181
  break
182
+ async with httpx.AsyncClient(timeout=10.0) as c:
183
+ if SELF_URL:
184
+ try:
185
+ await c.get(f"{SELF_URL}/keep-alive")
186
+ except Exception:
187
+ pass
188
+ try:
189
+ await c.get(ping_url, headers=ping_headers)
190
+ except Exception:
191
+ pass
192
  if not request_task.done():
193
  request_task.cancel()
194
  try:
 
231
  ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
232
  if user_token:
233
  ping_headers["X-API-Key"] = user_token
234
+ ping_task = _start_ping_task(f"{UPSTREAM_URL}/secure-ping/", ping_headers, SELF_URL)
235
  timeout = httpx.Timeout(UPSTREAM_TIMEOUT)
236
  client = httpx.AsyncClient(timeout=timeout, follow_redirects=True)
237
 
 
295
 
296
 
297
  async def _forward_multipart_json(path: str, files=None, data=None, user_token: str | None = None, method: str = "POST"):
298
+ """POST multipart to upstream and return JSON. While waiting: secure_ping to backend; if SELF_URL set, ping self."""
299
  url = f"{UPSTREAM_URL}{path}"
300
  headers = {
301
  "Authorization": f"Bearer {HF_TOKEN}",
 
303
  }
304
  if user_token:
305
  headers["X-API-Key"] = user_token
306
+ ping_url = f"{UPSTREAM_URL}/secure-ping/"
307
  ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
308
  if user_token:
309
  ping_headers["X-API-Key"] = user_token
 
317
 
318
  request_task = asyncio.create_task(do_request())
319
  interval = PING_UPSTREAM_INTERVAL if PING_UPSTREAM_INTERVAL > 0 else 0.0
320
+ wait_sec = (SELF_PING_INTERVAL if SELF_URL and SELF_PING_INTERVAL > 0 else interval) or interval
321
  try:
322
  while not request_task.done():
323
+ if wait_sec <= 0:
324
  await request_task
325
  break
326
+ ping_sleep = asyncio.create_task(asyncio.sleep(wait_sec))
327
  done, pending = await asyncio.wait(
328
  {request_task, ping_sleep},
329
  return_when=asyncio.FIRST_COMPLETED,
 
338
  pass
339
  if request_task in done:
340
  break
341
+ async with httpx.AsyncClient(timeout=10.0) as c:
342
+ if SELF_URL:
343
+ try:
344
+ await c.get(f"{SELF_URL}/keep-alive")
345
+ except Exception:
346
+ pass
347
+ try:
348
+ await c.get(ping_url, headers=ping_headers)
349
+ except Exception:
350
+ pass
351
  if not request_task.done():
352
  request_task.cancel()
353
  try: