mirror of
https://github.com/stellarshenson/stellars-jupyterhub-ds.git
synced 2026-03-08 06:00:29 +00:00
refactor: separate resource refresh from activity sampling
- Remove "Measured X ago" timer display (adds no value) - Change auto-refresh interval from 30s to 10s for real-time monitoring - Add JUPYTERHUB_ACTIVITYMON_RESOURCES_UPDATE_INTERVAL env var (default 10s) - Resource refresh updates status, CPU, memory, timers only - Activity sampling is separate (controlled by background process) - Remove formatTimeAgo function and related timestamp tracking
This commit is contained in:
@@ -198,3 +198,6 @@ This journal tracks substantive work on documents, diagrams, and documentation c
|
||||
|
||||
65. **Task - Activity table sorting and display improvements**: Added column sorting and improved Last Active display<br>
|
||||
**Result**: Added clickable column sorting for User, CPU, Memory, Time Left, Last Active columns. Sorting cycles through descending → ascending → none (default). Sort icons (▲/▼) show current direction. Default sort is activity score descending. Null values sorted to end. Changed Last Active display to match admin page format with full words ("8 minutes ago", "14 days ago", "4 months ago") with proper singular/plural handling
|
||||
|
||||
66. **Task - Activity Monitor resource refresh separation**: Separated resource updates from activity sampling with 10-second refresh interval<br>
|
||||
**Result**: **Major architectural change** - The Activity Monitor now has a clear separation between two distinct operations: (1) **Resource Updates** - Status (active/inactive/offline), CPU usage, memory usage, and idle culler timers are refreshed automatically every 10 seconds via frontend auto-refresh. This provides real-time monitoring without recording activity history. (2) **Activity Sampling** - Recording of user activity state for historical scoring is completely separate and will be controlled by a background process (not implemented yet). **UI Changes**: Removed "Measured X ago" timer display as it added no value and was confusing when data refreshed automatically. Removed lastMeasuredTimestamp tracking, measureTimeUpdateInterval timer, and formatTimeAgo function. Changed auto-refresh interval from 30 seconds to 10 seconds. **New Environment Variable**: Added `JUPYTERHUB_ACTIVITYMON_RESOURCES_UPDATE_INTERVAL` (default 10 seconds) to Dockerfile and settings_dictionary.yml for configuring resource refresh rate. **Key Clarification**: Viewing the Activity page or auto-refresh does NOT record activity samples - it only reads current state. Activity samples must be recorded by a separate mechanism (to be implemented) that runs independently of page views
|
||||
|
||||
@@ -90,6 +90,7 @@ ENV JUPYTERHUB_IDLE_CULLER_MAX_EXTENSION=24
|
||||
ENV JUPYTERHUB_ACTIVITYMON_RETENTION_DAYS=7
|
||||
ENV JUPYTERHUB_ACTIVITYMON_HALF_LIFE=24
|
||||
ENV JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER=60
|
||||
ENV JUPYTERHUB_ACTIVITYMON_RESOURCES_UPDATE_INTERVAL=10
|
||||
# Misc
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=3
|
||||
ENV STELLARS_JUPYTERHUB_VERSION=${VERSION}
|
||||
|
||||
@@ -93,6 +93,10 @@ Activity Monitor:
|
||||
description: Minutes until user considered inactive (1-1440)
|
||||
default: "60"
|
||||
|
||||
- name: JUPYTERHUB_ACTIVITYMON_RESOURCES_UPDATE_INTERVAL
|
||||
description: Resource refresh interval in seconds (status, CPU, memory)
|
||||
default: "10"
|
||||
|
||||
Branding:
|
||||
- name: JUPYTERHUB_LOGO_URI
|
||||
description: Custom logo URI
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<span class="badge bg-secondary" id="active-count">0 active servers</span>
|
||||
<span class="text-muted ms-2" id="last-updated"></span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-outline-danger btn-sm me-2" id="reset-btn">
|
||||
@@ -63,8 +62,6 @@ require(["jquery"], function($) {
|
||||
"use strict";
|
||||
|
||||
var autoRefreshInterval = null;
|
||||
var lastMeasuredTimestamp = null;
|
||||
var measureTimeUpdateInterval = null;
|
||||
var currentUsersData = []; // Store data for re-sorting
|
||||
var sortColumn = null; // Current sort column
|
||||
var sortDirection = null; // 'asc', 'desc', or null
|
||||
@@ -99,16 +96,8 @@ require(["jquery"], function($) {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-refresh data every 30 seconds
|
||||
autoRefreshInterval = setInterval(fetchActivityData, 30000);
|
||||
|
||||
// Update "Measured X ago" text every second
|
||||
measureTimeUpdateInterval = setInterval(function() {
|
||||
if (lastMeasuredTimestamp) {
|
||||
var timeAgo = formatTimeAgo(lastMeasuredTimestamp);
|
||||
$('#last-updated').text(timeAgo ? 'Measured ' + timeAgo : '');
|
||||
}
|
||||
}, 1000);
|
||||
// Auto-refresh resources every 10 seconds (status, CPU, memory, timers)
|
||||
autoRefreshInterval = setInterval(fetchActivityData, 10000);
|
||||
|
||||
// Manual refresh button
|
||||
$('#refresh-btn').on('click', function() {
|
||||
@@ -168,8 +157,6 @@ require(["jquery"], function($) {
|
||||
|
||||
function renderActivityTable(data) {
|
||||
var users = data.users || [];
|
||||
var timestamp = data.timestamp || new Date().toISOString();
|
||||
var samplingStatus = data.sampling_status || '';
|
||||
|
||||
$('#loading-indicator').hide();
|
||||
|
||||
@@ -184,14 +171,6 @@ require(["jquery"], function($) {
|
||||
|
||||
// Update header info
|
||||
$('#active-count').text(users.length + ' active server' + (users.length !== 1 ? 's' : ''));
|
||||
lastMeasuredTimestamp = timestamp;
|
||||
var timeAgo = formatTimeAgo(timestamp);
|
||||
$('#last-updated').text(timeAgo ? 'Measured ' + timeAgo : '');
|
||||
|
||||
// Show sampling status if available
|
||||
if (samplingStatus) {
|
||||
$('#sampling-status').html('<span class="badge bg-info">' + escapeHtml(samplingStatus) + '</span>');
|
||||
}
|
||||
|
||||
// Store data for sorting
|
||||
currentUsersData = users;
|
||||
@@ -372,28 +351,6 @@ require(["jquery"], function($) {
|
||||
return html;
|
||||
}
|
||||
|
||||
function formatTimeAgo(isoString) {
|
||||
var date = new Date(isoString);
|
||||
var now = new Date();
|
||||
var diffMs = now - date;
|
||||
var diffSec = Math.floor(diffMs / 1000);
|
||||
var diffMin = Math.floor(diffSec / 60);
|
||||
var diffHour = Math.floor(diffMin / 60);
|
||||
|
||||
if (diffSec <= 0) {
|
||||
return ''; // Display nothing for 0 or negative
|
||||
} else if (diffSec < 60) {
|
||||
return diffSec + 's ago';
|
||||
} else if (diffMin < 60) {
|
||||
return diffMin + 'min ago';
|
||||
} else if (diffHour < 24) {
|
||||
return diffHour + 'h ago';
|
||||
} else {
|
||||
var diffDay = Math.floor(diffHour / 24);
|
||||
return diffDay + 'd ago';
|
||||
}
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||
if (match) return match[2];
|
||||
|
||||
Reference in New Issue
Block a user