Spaces:
Runtime error
Runtime error
da03
commited on
Commit
·
4036b4b
1
Parent(s):
38d7454
- dispatcher.py +66 -6
- static/index.html +20 -3
dispatcher.py
CHANGED
|
@@ -228,21 +228,81 @@ class SessionManager:
|
|
| 228 |
session = self.sessions.get(session_id)
|
| 229 |
if session and session.status == SessionStatus.QUEUED:
|
| 230 |
try:
|
| 231 |
-
# Calculate estimated wait time
|
| 232 |
-
|
| 233 |
-
avg_session_time = self.MAX_SESSION_TIME_WITH_QUEUE if active_sessions_count > 0 else 30.0
|
| 234 |
-
estimated_wait = (i + 1) * avg_session_time / max(len(self.workers), 1)
|
| 235 |
|
| 236 |
await session.websocket.send_json({
|
| 237 |
"type": "queue_update",
|
| 238 |
"position": i + 1,
|
| 239 |
"total_waiting": len(self.session_queue),
|
| 240 |
"estimated_wait_seconds": estimated_wait,
|
| 241 |
-
"active_sessions":
|
|
|
|
| 242 |
})
|
| 243 |
except Exception as e:
|
| 244 |
logger.error(f"Failed to send queue update to session {session_id}: {e}")
|
| 245 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
async def handle_user_activity(self, session_id: str):
|
| 247 |
"""Update user activity timestamp"""
|
| 248 |
session = self.sessions.get(session_id)
|
|
@@ -428,7 +488,7 @@ async def periodic_queue_update():
|
|
| 428 |
while True:
|
| 429 |
try:
|
| 430 |
await session_manager.update_queue_info()
|
| 431 |
-
await asyncio.sleep(
|
| 432 |
except Exception as e:
|
| 433 |
logger.error(f"Error in periodic queue update: {e}")
|
| 434 |
|
|
|
|
| 228 |
session = self.sessions.get(session_id)
|
| 229 |
if session and session.status == SessionStatus.QUEUED:
|
| 230 |
try:
|
| 231 |
+
# Calculate dynamic estimated wait time
|
| 232 |
+
estimated_wait = self._calculate_dynamic_wait_time(i + 1)
|
|
|
|
|
|
|
| 233 |
|
| 234 |
await session.websocket.send_json({
|
| 235 |
"type": "queue_update",
|
| 236 |
"position": i + 1,
|
| 237 |
"total_waiting": len(self.session_queue),
|
| 238 |
"estimated_wait_seconds": estimated_wait,
|
| 239 |
+
"active_sessions": len(self.active_sessions),
|
| 240 |
+
"available_workers": len([w for w in self.workers.values() if w.is_available])
|
| 241 |
})
|
| 242 |
except Exception as e:
|
| 243 |
logger.error(f"Failed to send queue update to session {session_id}: {e}")
|
| 244 |
|
| 245 |
+
def _calculate_dynamic_wait_time(self, position_in_queue: int) -> float:
|
| 246 |
+
"""Calculate dynamic estimated wait time based on current session progress"""
|
| 247 |
+
current_time = time.time()
|
| 248 |
+
available_workers = len([w for w in self.workers.values() if w.is_available])
|
| 249 |
+
|
| 250 |
+
# If there are available workers, no wait time
|
| 251 |
+
if available_workers > 0:
|
| 252 |
+
return 0
|
| 253 |
+
|
| 254 |
+
# Calculate remaining time for active sessions
|
| 255 |
+
min_remaining_time = float('inf')
|
| 256 |
+
active_session_times = []
|
| 257 |
+
|
| 258 |
+
for session_id in self.active_sessions:
|
| 259 |
+
session = self.sessions.get(session_id)
|
| 260 |
+
if session and session.last_activity:
|
| 261 |
+
if session.max_session_time:
|
| 262 |
+
# Session has time limit (queue exists)
|
| 263 |
+
elapsed = current_time - session.last_activity
|
| 264 |
+
remaining = session.max_session_time - elapsed
|
| 265 |
+
remaining = max(0, remaining) # Don't go negative
|
| 266 |
+
else:
|
| 267 |
+
# No time limit, estimate based on average usage
|
| 268 |
+
elapsed = current_time - session.last_activity
|
| 269 |
+
# Assume sessions without time limits will run for average of 45 seconds more
|
| 270 |
+
remaining = max(45 - elapsed, 10) # Minimum 10 seconds
|
| 271 |
+
|
| 272 |
+
active_session_times.append(remaining)
|
| 273 |
+
min_remaining_time = min(min_remaining_time, remaining)
|
| 274 |
+
|
| 275 |
+
# If no active sessions found, use default
|
| 276 |
+
if not active_session_times:
|
| 277 |
+
min_remaining_time = 30.0
|
| 278 |
+
|
| 279 |
+
# Calculate estimated wait time based on position
|
| 280 |
+
num_workers = len(self.workers)
|
| 281 |
+
if num_workers == 0:
|
| 282 |
+
return 999 # No workers available
|
| 283 |
+
|
| 284 |
+
if position_in_queue <= num_workers:
|
| 285 |
+
# User will get a worker as soon as current sessions end
|
| 286 |
+
return min_remaining_time
|
| 287 |
+
else:
|
| 288 |
+
# User needs to wait for multiple session cycles
|
| 289 |
+
cycles_to_wait = (position_in_queue - 1) // num_workers
|
| 290 |
+
remaining_in_current_cycle = (position_in_queue - 1) % num_workers + 1
|
| 291 |
+
|
| 292 |
+
# Time for complete cycles (use average session time)
|
| 293 |
+
avg_session_time = self.MAX_SESSION_TIME_WITH_QUEUE if len(self.session_queue) > 0 else 45.0
|
| 294 |
+
full_cycles_time = cycles_to_wait * avg_session_time
|
| 295 |
+
|
| 296 |
+
# Time for current partial cycle
|
| 297 |
+
if remaining_in_current_cycle <= len(active_session_times):
|
| 298 |
+
# Sort session times to get when the Nth worker will be free
|
| 299 |
+
sorted_times = sorted(active_session_times)
|
| 300 |
+
current_cycle_time = sorted_times[remaining_in_current_cycle - 1]
|
| 301 |
+
else:
|
| 302 |
+
current_cycle_time = min_remaining_time
|
| 303 |
+
|
| 304 |
+
return full_cycles_time + current_cycle_time
|
| 305 |
+
|
| 306 |
async def handle_user_activity(self, session_id: str):
|
| 307 |
"""Update user activity timestamp"""
|
| 308 |
session = self.sessions.get(session_id)
|
|
|
|
| 488 |
while True:
|
| 489 |
try:
|
| 490 |
await session_manager.update_queue_info()
|
| 491 |
+
await asyncio.sleep(2) # Update every 2 seconds for responsive experience
|
| 492 |
except Exception as e:
|
| 493 |
logger.error(f"Error in periodic queue update: {e}")
|
| 494 |
|
static/index.html
CHANGED
|
@@ -282,10 +282,27 @@
|
|
| 282 |
} else if (data.type === "queue_update") {
|
| 283 |
console.log(`Queue update: Position ${data.position}/${data.total_waiting}, estimated wait: ${data.estimated_wait_seconds.toFixed(1)} seconds`);
|
| 284 |
const waitSeconds = Math.ceil(data.estimated_wait_seconds);
|
| 285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
showConnectionStatus(
|
| 287 |
-
|
| 288 |
-
`Estimated wait
|
| 289 |
);
|
| 290 |
} else if (data.type === "session_start") {
|
| 291 |
console.log("Session started, clearing queue display");
|
|
|
|
| 282 |
} else if (data.type === "queue_update") {
|
| 283 |
console.log(`Queue update: Position ${data.position}/${data.total_waiting}, estimated wait: ${data.estimated_wait_seconds.toFixed(1)} seconds`);
|
| 284 |
const waitSeconds = Math.ceil(data.estimated_wait_seconds);
|
| 285 |
+
|
| 286 |
+
let waitText;
|
| 287 |
+
if (waitSeconds === 0) {
|
| 288 |
+
waitText = "Starting soon...";
|
| 289 |
+
} else if (waitSeconds === 1) {
|
| 290 |
+
waitText = "1 second";
|
| 291 |
+
} else if (waitSeconds < 60) {
|
| 292 |
+
waitText = `${waitSeconds} seconds`;
|
| 293 |
+
} else {
|
| 294 |
+
const minutes = Math.floor(waitSeconds / 60);
|
| 295 |
+
const seconds = waitSeconds % 60;
|
| 296 |
+
waitText = `${minutes}m ${seconds}s`;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
const statusText = data.available_workers > 0 ?
|
| 300 |
+
"Processing queue..." :
|
| 301 |
+
`Position ${data.position} in queue`;
|
| 302 |
+
|
| 303 |
showConnectionStatus(
|
| 304 |
+
statusText,
|
| 305 |
+
`Estimated wait: ${waitText} (${data.active_sessions} active sessions)`
|
| 306 |
);
|
| 307 |
} else if (data.type === "session_start") {
|
| 308 |
console.log("Session started, clearing queue display");
|