Browse Source

better jobs dashboard with faster refresh

Nick Sweeting 1 year ago
parent
commit
c7bd9449d5
2 changed files with 77 additions and 16 deletions
  1. 57 10
      archivebox/actors/templates/jobs_dashboard.html
  2. 20 6
      archivebox/api/v1_actors.py

+ 57 - 10
archivebox/actors/templates/jobs_dashboard.html

@@ -13,9 +13,18 @@
             margin: 0 auto;
             padding: 20px;
         }
+        @keyframes pulse {
+            0% { opacity: 1; }
+            48% { opacity: 0.2; }
+            52% { opacity: 1; }
+            100% { opacity: 1; }
+        }
         h1 {
             text-align: center;
         }
+        h1 a {
+            animation: pulse 1s;
+        }
         .dashboard {
             display: grid;
             grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
@@ -85,13 +94,21 @@
     </style>
 </head>
 <body>
-    <h1>Job Dashboard <small><a href="?refresh=true">♻️ {{now}}</a></small></h1>
+    <h1>Job Dashboard <small><a href="?refresh=true" id="current-time">♻️ {{now}}}</a></small></h1>
     <div id="dashboard" class="dashboard"></div>
 
     <script>
         function formatDate(dateString) {
+            const now = Date.now()
+            const date = new Date(dateString)
             // return new Date(dateString).toLocaleString();
-            return new Date(dateString).toISOString().split('T').at(-1).replace('Z', '');
+            // return date.toISOString().split('T').at(-1).replace('Z', '');
+            const seconds_diff = Math.round((date - now) / 1000, 0)
+            if (seconds_diff < 0) {
+                return `${seconds_diff}s ago`;
+            } else {
+                return `${seconds_diff}s in the future`;
+            }
         }
 
         function createJobElement(job) {
@@ -109,6 +126,10 @@
         }
 
         function updateDashboard(data) {
+            const currentTime = document.getElementById('current-time');
+            window.now = new Date();
+            currentTime.innerHTML = `♻️ ${window.now.toISOString().split('T').at(-1).replace('Z', '')}`;
+
             const dashboard = document.getElementById('dashboard');
             dashboard.innerHTML = '';
 
@@ -117,16 +138,42 @@
                 card.className = 'card';
                 card.innerHTML = `
                     <h2>${actor.model}</h2>
-                    <h3>Queue</h3>
-                    <div class="scroll-area" id="queue-${actor.model}"></div>
-                    <h3>Past Tasks</h3>
-                    <div class="scroll-area" id="past-${actor.model}"></div>
+                    <hr/>
+                    Future
+                    <div class="scroll-area" style="background-color: white;" id="future-${actor.model}"></div>
+                    <hr/>
+                    Pending
+                    <div class="scroll-area" style="background-color: lightblue;" id="pending-${actor.model}"></div>
+                    <hr/>
+                    Stalled
+                    <div class="scroll-area" style="background-color: lightcoral;" id="stalled-${actor.model}"></div>
+                    <hr/>
+                    Active
+                    <div class="scroll-area" style="background-color: lightgreen;" id="active-${actor.model}"></div>
+                    <hr/>
+                    Past
+                    <div class="scroll-area" style="background-color: lightgrey;" id="past-${actor.model}"></div>
                 `;
                 dashboard.appendChild(card);
 
-                const queueContainer = document.getElementById(`queue-${actor.model}`);
-                actor.queue.forEach(job => {
-                    queueContainer.appendChild(createJobElement(job));
+                const futureContainer = document.getElementById(`future-${actor.model}`);
+                actor.future.forEach(job => {
+                    futureContainer.appendChild(createJobElement(job));
+                });
+
+                const pendingContainer = document.getElementById(`pending-${actor.model}`);
+                actor.pending.forEach(job => {
+                    pendingContainer.appendChild(createJobElement(job));
+                });
+
+                const stalledContainer = document.getElementById(`stalled-${actor.model}`);
+                actor.stalled.forEach(job => {
+                    stalledContainer.appendChild(createJobElement(job));
+                });
+
+                const activeContainer = document.getElementById(`active-${actor.model}`);
+                actor.active.forEach(job => {
+                    activeContainer.appendChild(createJobElement(job));
                 });
 
                 const pastContainer = document.getElementById(`past-${actor.model}`);
@@ -149,7 +196,7 @@
 
         fetchData();
 
-        setInterval(fetchData, 1000);
+        setInterval(fetchData, 750);
     </script>
 </body>
 </html>

+ 20 - 6
archivebox/api/v1_actors.py

@@ -7,9 +7,8 @@ from datetime import datetime
 
 from ninja import Router, Schema
 
-from .auth import API_AUTH_METHODS
 
-router = Router(tags=['Workers and Tasks'], auth=API_AUTH_METHODS)
+router = Router(tags=['Workers and Tasks'])
 
 
 class TaskSchema(Schema):
@@ -50,7 +49,10 @@ class ActorSchema(Schema):
     MAX_TICK_TIME: int
     MAX_CONCURRENT_ACTORS: int
     
-    queue: list[TaskSchema]
+    future: list[TaskSchema]
+    pending: list[TaskSchema]
+    stalled: list[TaskSchema]
+    active: list[TaskSchema]
     past: list[TaskSchema]
     
     @staticmethod
@@ -72,10 +74,22 @@ class ActorSchema(Schema):
     @staticmethod
     def resolve_FINAL_STATES(obj) -> list[str]:
         return [str(state) for state in obj.FINAL_STATES]
-
+    
+    @staticmethod
+    def resolve_future(obj) -> list[TaskSchema]:
+        return [obj for obj in obj.qs.filter(obj.future_q).order_by('-retry_at')]
+    
+    @staticmethod
+    def resolve_pending(obj) -> list[TaskSchema]:
+        return [obj for obj in obj.qs.filter(obj.pending_q).order_by('-retry_at')]
+    
+    @staticmethod
+    def resolve_stalled(obj) -> list[TaskSchema]:
+        return [obj for obj in obj.qs.filter(obj.stalled_q).order_by('-retry_at')]
+    
     @staticmethod
-    def resolve_queue(obj) -> list[TaskSchema]:
-        return [obj for obj in obj.qs.filter(obj.pending_q | obj.future_q | obj.active_q | obj.stalled_q).order_by('-retry_at')]
+    def resolve_active(obj) -> list[TaskSchema]:
+        return [obj for obj in obj.qs.filter(obj.active_q).order_by('-retry_at')]
 
     @staticmethod
     def resolve_past(obj) -> list[TaskSchema]: