Spaces:
Runtime error
Runtime error
da03
commited on
Commit
·
12c4b52
1
Parent(s):
4555c1c
- dispatcher.py +44 -10
- static/index.html +54 -16
dispatcher.py
CHANGED
@@ -388,19 +388,15 @@ class SessionManager:
|
|
388 |
return None
|
389 |
|
390 |
async def add_session_to_queue(self, session: UserSession):
|
391 |
-
"""Add a session to the queue"""
|
392 |
-
# Check if queue was empty before adding this session
|
393 |
-
was_queue_empty = len(self.session_queue) == 0
|
394 |
-
|
395 |
self.sessions[session.session_id] = session
|
396 |
self.session_queue.append(session.session_id)
|
397 |
session.status = SessionStatus.QUEUED
|
398 |
session.queue_start_time = time.time()
|
399 |
logger.info(f"Added session {session.session_id} to queue. Queue size: {len(self.session_queue)}")
|
400 |
|
401 |
-
#
|
402 |
-
if
|
403 |
-
await self.apply_queue_limits_to_existing_sessions()
|
404 |
|
405 |
async def apply_queue_limits_to_existing_sessions(self):
|
406 |
"""Apply 60-second time limits to existing unlimited sessions when queue forms"""
|
@@ -420,11 +416,9 @@ class SessionManager:
|
|
420 |
# Notify the user about the new time limit
|
421 |
try:
|
422 |
queue_size = len(self.session_queue)
|
423 |
-
message = f"Other users waiting. Time remaining: 60 seconds."
|
424 |
|
425 |
await session.websocket.send_json({
|
426 |
"type": "queue_limit_applied",
|
427 |
-
"message": message,
|
428 |
"time_remaining": 60.0,
|
429 |
"queue_size": queue_size
|
430 |
})
|
@@ -435,8 +429,39 @@ class SessionManager:
|
|
435 |
if affected_sessions > 0:
|
436 |
analytics.log_queue_limits_applied(affected_sessions, len(self.session_queue))
|
437 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
438 |
async def process_queue(self):
|
439 |
"""Process the session queue"""
|
|
|
|
|
|
|
440 |
while self.session_queue:
|
441 |
session_id = self.session_queue[0]
|
442 |
session = self.sessions.get(session_id)
|
@@ -462,7 +487,7 @@ class SessionManager:
|
|
462 |
session.worker_id = worker.worker_id
|
463 |
session.last_activity = time.time()
|
464 |
|
465 |
-
# Set session time limit based on queue status
|
466 |
if len(self.session_queue) > 0:
|
467 |
session.max_session_time = self.MAX_SESSION_TIME_WITH_QUEUE
|
468 |
session.session_limit_start_time = time.time() # Track when limit started
|
@@ -500,6 +525,15 @@ class SessionManager:
|
|
500 |
|
501 |
# Start session monitoring
|
502 |
asyncio.create_task(self.monitor_active_session(session_id))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
503 |
|
504 |
async def notify_session_start(self, session: UserSession):
|
505 |
"""Notify user that their session is starting"""
|
|
|
388 |
return None
|
389 |
|
390 |
async def add_session_to_queue(self, session: UserSession):
|
391 |
+
"""Add a session to the queue"""
|
|
|
|
|
|
|
392 |
self.sessions[session.session_id] = session
|
393 |
self.session_queue.append(session.session_id)
|
394 |
session.status = SessionStatus.QUEUED
|
395 |
session.queue_start_time = time.time()
|
396 |
logger.info(f"Added session {session.session_id} to queue. Queue size: {len(self.session_queue)}")
|
397 |
|
398 |
+
# Don't apply time limits here - wait until after processing queue
|
399 |
+
# to see if users actually have to wait
|
|
|
400 |
|
401 |
async def apply_queue_limits_to_existing_sessions(self):
|
402 |
"""Apply 60-second time limits to existing unlimited sessions when queue forms"""
|
|
|
416 |
# Notify the user about the new time limit
|
417 |
try:
|
418 |
queue_size = len(self.session_queue)
|
|
|
419 |
|
420 |
await session.websocket.send_json({
|
421 |
"type": "queue_limit_applied",
|
|
|
422 |
"time_remaining": 60.0,
|
423 |
"queue_size": queue_size
|
424 |
})
|
|
|
429 |
if affected_sessions > 0:
|
430 |
analytics.log_queue_limits_applied(affected_sessions, len(self.session_queue))
|
431 |
|
432 |
+
async def remove_time_limits_if_queue_empty(self):
|
433 |
+
"""Remove time limits from active sessions when queue becomes empty"""
|
434 |
+
if len(self.session_queue) > 0:
|
435 |
+
return # Queue not empty, don't remove limits
|
436 |
+
|
437 |
+
removed_limits = 0
|
438 |
+
for session_id in list(self.active_sessions.keys()):
|
439 |
+
session = self.sessions.get(session_id)
|
440 |
+
if session and session.max_session_time is not None:
|
441 |
+
# Remove time limit
|
442 |
+
session.max_session_time = None
|
443 |
+
session.session_limit_start_time = None
|
444 |
+
session.session_warning_sent = False
|
445 |
+
removed_limits += 1
|
446 |
+
|
447 |
+
# Notify user that time limit was removed
|
448 |
+
try:
|
449 |
+
await session.websocket.send_json({
|
450 |
+
"type": "time_limit_removed",
|
451 |
+
"reason": "queue_empty"
|
452 |
+
})
|
453 |
+
logger.info(f"Time limit removed from active session {session_id} (queue empty)")
|
454 |
+
except Exception as e:
|
455 |
+
logger.error(f"Failed to notify session {session_id} about time limit removal: {e}")
|
456 |
+
|
457 |
+
if removed_limits > 0:
|
458 |
+
logger.info(f"Removed time limits from {removed_limits} active sessions (queue became empty)")
|
459 |
+
|
460 |
async def process_queue(self):
|
461 |
"""Process the session queue"""
|
462 |
+
# Track if we had any existing active sessions before processing
|
463 |
+
had_active_sessions = len(self.active_sessions) > 0
|
464 |
+
|
465 |
while self.session_queue:
|
466 |
session_id = self.session_queue[0]
|
467 |
session = self.sessions.get(session_id)
|
|
|
487 |
session.worker_id = worker.worker_id
|
488 |
session.last_activity = time.time()
|
489 |
|
490 |
+
# Set session time limit based on queue status AFTER processing
|
491 |
if len(self.session_queue) > 0:
|
492 |
session.max_session_time = self.MAX_SESSION_TIME_WITH_QUEUE
|
493 |
session.session_limit_start_time = time.time() # Track when limit started
|
|
|
525 |
|
526 |
# Start session monitoring
|
527 |
asyncio.create_task(self.monitor_active_session(session_id))
|
528 |
+
|
529 |
+
# After processing queue, if there are still users waiting AND we had existing active sessions,
|
530 |
+
# apply time limits to those existing sessions
|
531 |
+
if len(self.session_queue) > 0 and had_active_sessions:
|
532 |
+
await self.apply_queue_limits_to_existing_sessions()
|
533 |
+
|
534 |
+
# If queue became empty and there are active sessions with time limits, remove them
|
535 |
+
elif len(self.session_queue) == 0:
|
536 |
+
await self.remove_time_limits_if_queue_empty()
|
537 |
|
538 |
async def notify_session_start(self, session: UserSession):
|
539 |
"""Notify user that their session is starting"""
|
static/index.html
CHANGED
@@ -280,29 +280,19 @@
|
|
280 |
console.log("Server detected user activity, resetting timeout");
|
281 |
stopTimeoutCountdown();
|
282 |
} else if (data.type === "queue_update") {
|
283 |
-
console.log(`Queue update: Position ${data.position}/${data.total_waiting},
|
284 |
const waitSeconds = Math.ceil(data.maximum_wait_seconds);
|
285 |
|
286 |
-
let waitText;
|
287 |
if (waitSeconds === 0) {
|
288 |
-
|
289 |
-
|
290 |
-
waitText = "1 second max";
|
291 |
} else {
|
292 |
-
|
293 |
}
|
294 |
-
|
295 |
-
const statusText = data.available_workers > 0 ?
|
296 |
-
"Processing queue..." :
|
297 |
-
`Position ${data.position} in queue`;
|
298 |
-
|
299 |
-
showConnectionStatus(
|
300 |
-
statusText,
|
301 |
-
`Maximum wait: ${waitText} (${data.active_sessions} active sessions)`
|
302 |
-
);
|
303 |
} else if (data.type === "session_start") {
|
304 |
console.log("Session started, clearing queue display");
|
305 |
-
//
|
|
|
306 |
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
307 |
} else if (data.type === "session_warning") {
|
308 |
console.log(`Session time warning: ${data.time_remaining} seconds remaining`);
|
@@ -374,6 +364,11 @@
|
|
374 |
let timeoutCountdown = 10;
|
375 |
let timeoutWarningActive = false;
|
376 |
|
|
|
|
|
|
|
|
|
|
|
377 |
function startAutoInput() {
|
378 |
if (autoInputInterval) {
|
379 |
clearInterval(autoInputInterval);
|
@@ -522,6 +517,48 @@
|
|
522 |
}
|
523 |
}
|
524 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
525 |
function setTimeoutMessage(message) {
|
526 |
const messageElement = document.getElementById('timeoutMessage');
|
527 |
if (messageElement) {
|
@@ -735,6 +772,7 @@
|
|
735 |
window.addEventListener('beforeunload', function (e) {
|
736 |
stopAutoInput(); // Clean up auto-input interval
|
737 |
stopTimeoutCountdown(); // Clean up timeout countdown
|
|
|
738 |
if (isConnected) {
|
739 |
try {
|
740 |
//socket.send(JSON.stringify({ type: "disconnect" }));
|
|
|
280 |
console.log("Server detected user activity, resetting timeout");
|
281 |
stopTimeoutCountdown();
|
282 |
} else if (data.type === "queue_update") {
|
283 |
+
console.log(`Queue update: Position ${data.position}/${data.total_waiting}, wait: ${data.maximum_wait_seconds.toFixed(1)} seconds`);
|
284 |
const waitSeconds = Math.ceil(data.maximum_wait_seconds);
|
285 |
|
|
|
286 |
if (waitSeconds === 0) {
|
287 |
+
showConnectionStatus("Starting soon...");
|
288 |
+
stopQueueCountdown();
|
|
|
289 |
} else {
|
290 |
+
startQueueCountdown(waitSeconds);
|
291 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
292 |
} else if (data.type === "session_start") {
|
293 |
console.log("Session started, clearing queue display");
|
294 |
+
// Stop queue countdown and clear the display
|
295 |
+
stopQueueCountdown();
|
296 |
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
297 |
} else if (data.type === "session_warning") {
|
298 |
console.log(`Session time warning: ${data.time_remaining} seconds remaining`);
|
|
|
364 |
let timeoutCountdown = 10;
|
365 |
let timeoutWarningActive = false;
|
366 |
|
367 |
+
// Queue waiting countdown mechanism
|
368 |
+
let queueCountdownInterval = null;
|
369 |
+
let queueWaitTime = 0;
|
370 |
+
let queueCountdownActive = false;
|
371 |
+
|
372 |
function startAutoInput() {
|
373 |
if (autoInputInterval) {
|
374 |
clearInterval(autoInputInterval);
|
|
|
517 |
}
|
518 |
}
|
519 |
|
520 |
+
function startQueueCountdown(initialWaitTime) {
|
521 |
+
if (queueCountdownInterval) {
|
522 |
+
clearInterval(queueCountdownInterval);
|
523 |
+
}
|
524 |
+
|
525 |
+
queueWaitTime = initialWaitTime;
|
526 |
+
queueCountdownActive = true;
|
527 |
+
|
528 |
+
// Show initial countdown
|
529 |
+
updateQueueCountdownDisplay();
|
530 |
+
|
531 |
+
// Start countdown
|
532 |
+
queueCountdownInterval = setInterval(() => {
|
533 |
+
queueWaitTime--;
|
534 |
+
updateQueueCountdownDisplay();
|
535 |
+
|
536 |
+
if (queueWaitTime <= 0) {
|
537 |
+
stopQueueCountdown();
|
538 |
+
showConnectionStatus("Starting soon...");
|
539 |
+
}
|
540 |
+
}, 1000);
|
541 |
+
}
|
542 |
+
|
543 |
+
function stopQueueCountdown() {
|
544 |
+
if (queueCountdownInterval) {
|
545 |
+
clearInterval(queueCountdownInterval);
|
546 |
+
queueCountdownInterval = null;
|
547 |
+
}
|
548 |
+
queueCountdownActive = false;
|
549 |
+
queueWaitTime = 0;
|
550 |
+
}
|
551 |
+
|
552 |
+
function updateQueueCountdownDisplay() {
|
553 |
+
if (queueWaitTime <= 0) {
|
554 |
+
showConnectionStatus("Starting soon...");
|
555 |
+
} else if (queueWaitTime === 1) {
|
556 |
+
showConnectionStatus("Estimated wait: 1 second");
|
557 |
+
} else {
|
558 |
+
showConnectionStatus(`Estimated wait: ${queueWaitTime} seconds`);
|
559 |
+
}
|
560 |
+
}
|
561 |
+
|
562 |
function setTimeoutMessage(message) {
|
563 |
const messageElement = document.getElementById('timeoutMessage');
|
564 |
if (messageElement) {
|
|
|
772 |
window.addEventListener('beforeunload', function (e) {
|
773 |
stopAutoInput(); // Clean up auto-input interval
|
774 |
stopTimeoutCountdown(); // Clean up timeout countdown
|
775 |
+
stopQueueCountdown(); // Clean up queue countdown
|
776 |
if (isConnected) {
|
777 |
try {
|
778 |
//socket.send(JSON.stringify({ type: "disconnect" }));
|