Rajhuggingface4253 commited on
Commit
c5ed1b4
Β·
verified Β·
1 Parent(s): 69255b9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +229 -0
app.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.responses import HTMLResponse, JSONResponse
3
+ import httpx
4
+ import asyncio
5
+ import time
6
+ from datetime import datetime
7
+ from typing import Dict, List
8
+ import os
9
+
10
+ app = FastAPI(title="FastAPI Pinger", description="High-performance server warming service")
11
+
12
+ # Configuration
13
+ PING_INTERVAL = 300 # 5 minutes
14
+ HEALTH_CHECK_INTERVAL = 1800 # 30 minutes
15
+
16
+ # List of other pinger Spaces (add your Space URLs here)
17
+ pinger_spaces = [
18
+ "https://rajhuggingface4253-ping.hf.space",
19
+
20
+ ]
21
+
22
+ # Your target servers to keep warm
23
+ target_servers = [
24
+ "https://rajhuggingface4253-qwen.hf.space",
25
+ "https://rajhuggingface4253-qwen2.hf.space",
26
+ "https://rajhuggingface4253-qwen3.hf.space",
27
+ "https://rajhuggingface4253-backend-compressorpro.hf.space",
28
+ "https://rajhuggingface4253-backend-compressorpro2.hf.space"
29
+ "https://rajhuggingface4253-compressor3pro.hf.space"
30
+ "https://rajhuggingface4253-koko.hf.space"
31
+ ]
32
+
33
+ # Global state
34
+ ping_results: Dict[str, Dict] = {}
35
+ health_results: Dict[str, Dict] = {}
36
+ last_ping_run: datetime = None
37
+
38
+ async def ping_server(url: str) -> Dict:
39
+ """Ping a single server asynchronously"""
40
+ try:
41
+ start_time = time.time()
42
+ async with httpx.AsyncClient(timeout=10.0) as client:
43
+ full_url = url if '://' in url else f'https://{url}'
44
+ response = await client.get(full_url)
45
+ response_time = round((time.time() - start_time) * 1000, 1)
46
+
47
+ return {
48
+ 'status': 'success',
49
+ 'response_time_ms': response_time,
50
+ 'status_code': response.status_code,
51
+ 'timestamp': datetime.now().isoformat()
52
+ }
53
+ except Exception as e:
54
+ return {
55
+ 'status': 'error',
56
+ 'error': str(e),
57
+ 'timestamp': datetime.now().isoformat()
58
+ }
59
+
60
+ async def ping_all_servers():
61
+ """Ping all target servers concurrently"""
62
+ global ping_results, last_ping_run
63
+
64
+ tasks = [ping_server(server) for server in target_servers]
65
+ results = await asyncio.gather(*tasks)
66
+
67
+ # Store results
68
+ for i, server in enumerate(target_servers):
69
+ ping_results[server] = results[i]
70
+
71
+ last_ping_run = datetime.now()
72
+
73
+ # Log results
74
+ success_count = sum(1 for result in results if result['status'] == 'success')
75
+ print(f"{datetime.now().strftime('%H:%M:%S')} - {success_count}/{len(target_servers)} servers OK")
76
+
77
+ return results
78
+
79
+ async def ping_health_endpoints():
80
+ """Ping other pinger Spaces concurrently"""
81
+ global health_results
82
+
83
+ async with httpx.AsyncClient(timeout=10.0) as client:
84
+ tasks = []
85
+ for space_url in pinger_spaces:
86
+ health_url = f"{space_url}/health"
87
+ tasks.append(ping_single_health(client, space_url, health_url))
88
+
89
+ await asyncio.gather(*tasks)
90
+
91
+ async def ping_single_health(client: httpx.AsyncClient, space_url: str, health_url: str):
92
+ """Ping a single health endpoint"""
93
+ try:
94
+ start_time = time.time()
95
+ response = await client.get(health_url)
96
+ response_time = round((time.time() - start_time) * 1000, 1)
97
+
98
+ health_results[space_url] = {
99
+ 'status': 'success',
100
+ 'response_time_ms': response_time,
101
+ 'status_code': response.status_code,
102
+ 'last_ping': datetime.now().isoformat()
103
+ }
104
+ print(f"βœ… Health ping to {space_url}: {response_time}ms")
105
+ except Exception as e:
106
+ health_results[space_url] = {
107
+ 'status': 'error',
108
+ 'error': str(e),
109
+ 'last_ping': datetime.now().isoformat()
110
+ }
111
+ print(f"❌ Health ping failed for {space_url}: {e}")
112
+
113
+ async def continuous_pinging():
114
+ """Main pinging loop"""
115
+ print("πŸš€ FastAPI Pinger Started!")
116
+ print(f"πŸ“Š Monitoring {len(target_servers)} target servers")
117
+ print(f"πŸ”— Connected to {len(pinger_spaces)} pinger spaces")
118
+ print(f"⏰ Pinging every {PING_INTERVAL//60} minutes")
119
+
120
+ last_health_check = 0
121
+
122
+ while True:
123
+ try:
124
+ # Ping target servers
125
+ await ping_all_servers()
126
+
127
+ # Ping health endpoints every 30 minutes
128
+ current_time = time.time()
129
+ if current_time - last_health_check >= HEALTH_CHECK_INTERVAL:
130
+ if pinger_spaces:
131
+ print("πŸ”„ Pinging other pinger spaces...")
132
+ await ping_health_endpoints()
133
+ last_health_check = current_time
134
+
135
+ # Wait for next cycle
136
+ await asyncio.sleep(PING_INTERVAL)
137
+
138
+ except Exception as e:
139
+ print(f"❌ Error in pinging loop: {e}")
140
+ await asyncio.sleep(60) # Wait 1 minute before retrying
141
+
142
+ @app.on_event("startup")
143
+ async def startup_event():
144
+ """Start the pinging loop when the app starts"""
145
+ asyncio.create_task(continuous_pinging())
146
+
147
+ @app.get("/", response_class=HTMLResponse)
148
+ async def home():
149
+ """Main dashboard"""
150
+ success_count = sum(1 for result in ping_results.values() if result.get('status') == 'success')
151
+ health_success = sum(1 for result in health_results.values() if result.get('status') == 'success')
152
+
153
+ html_content = f"""
154
+ <html>
155
+ <head>
156
+ <title>FastAPI Pinger</title>
157
+ <style>
158
+ body {{ font-family: Arial, sans-serif; margin: 40px; }}
159
+ .success {{ color: green; }}
160
+ .error {{ color: red; }}
161
+ .container {{ max-width: 800px; margin: 0 auto; }}
162
+ </style>
163
+ </head>
164
+ <body>
165
+ <div class="container">
166
+ <h1>⚑ FastAPI Pinger</h1>
167
+ <p><strong>Target Servers:</strong> {len(target_servers)}</p>
168
+ <p><strong>Pinger Network:</strong> {len(pinger_spaces)}</p>
169
+ <p><strong>Last Run:</strong> {last_ping_run.strftime('%Y-%m-%d %H:%M:%S') if last_ping_run else 'Not yet'}</p>
170
+ <p><strong>Status:</strong> {success_count}/{len(target_servers)} servers OK β€’ {health_success}/{len(pinger_spaces)} pingers OK</p>
171
+
172
+ <h3>Endpoints:</h3>
173
+ <ul>
174
+ <li><a href="error</a></li>
175
+ </ul>
176
+ </div>
177
+ </body>
178
+ </html>
179
+ """
180
+ return HTMLResponse(content=html_content)
181
+
182
+ @app.get("/health")
183
+ async def health():
184
+ """Health endpoint for other pingers"""
185
+ return JSONResponse({
186
+ "status": "healthy",
187
+ "service": "fastapi-pinger",
188
+ "timestamp": datetime.now().isoformat(),
189
+ "server_count": len(target_servers),
190
+ "network_count": len(pinger_spaces),
191
+ "last_ping": last_ping_run.isoformat() if last_ping_run else None
192
+ })
193
+
194
+ @app.get("/results")
195
+ async def get_results():
196
+ """Get current ping results"""
197
+ return JSONResponse({
198
+ "last_run": last_ping_run.isoformat() if last_ping_run else None,
199
+ "target_servers": ping_results,
200
+ "pinger_network": health_results,
201
+ "timestamp": datetime.now().isoformat()
202
+ })
203
+
204
+ @app.get("/ping-now")
205
+ async def ping_now():
206
+ """Manually trigger a ping cycle"""
207
+ results = await ping_all_servers()
208
+ if pinger_spaces:
209
+ await ping_health_endpoints()
210
+
211
+ success_count = sum(1 for result in results if result['status'] == 'success')
212
+ health_success = sum(1 for result in health_results.values() if result.get('status') == 'success')
213
+
214
+ return JSONResponse({
215
+ "message": "Manual ping completed",
216
+ "servers_ok": f"{success_count}/{len(target_servers)}",
217
+ "pingers_ok": f"{health_success}/{len(pinger_spaces)}",
218
+ "timestamp": datetime.now().isoformat()
219
+ })
220
+
221
+ @app.get("/docs")
222
+ async def get_docs():
223
+ """Redirect to interactive docs"""
224
+ from fastapi.responses import RedirectResponse
225
+ return RedirectResponse(url="/docs")
226
+
227
+ if __name__ == "__main__":
228
+ import uvicorn
229
+ uvicorn.run(app, host="0.0.0.0", port=7860)