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" }));
|