Browse Source

Resolve "display job errors in webui"

Eric Tröbs 3 years ago
parent
commit
10e4d78382

+ 17 - 0
labels/failing_label_provider/Provider.py

@@ -0,0 +1,17 @@
+import typing
+from time import sleep
+
+from pycs.interfaces.LabelProvider import LabelProvider
+
+
+class Provider(LabelProvider):
+    def __init__(self, root_folder, configuration):
+        pass
+
+    def close(self):
+        pass
+
+    def get_labels(self) -> typing.List[dict]:
+        sleep(5)
+        raise ValueError('failed after five seconds')
+        return []

+ 8 - 0
labels/failing_label_provider/configuration.json

@@ -0,0 +1,8 @@
+{
+  "name": "Failing Label Provider v1",
+  "description": "fails after five seconds",
+  "code": {
+    "module": "Provider",
+    "class": "Provider"
+  }
+}

+ 1 - 0
pycs/jobs/Job.py

@@ -15,6 +15,7 @@ class Job:
         self.project_id = project.identifier
         self.type = job_type
         self.name = name
+        self.exception = None
         self.progress = 0
         self.created = int(time())
         self.updated = int(time())

+ 53 - 48
pycs/jobs/JobRunner.py

@@ -175,54 +175,59 @@ class JobRunner:
                 callback(job)
 
             # run function and track progress
-            generator = pool.spawn(executable, *args, **kwargs).wait()
-            result = generator
-
-            if isinstance(generator, GeneratorType):
-                iterator = iter(generator)
-
-                try:
-                    while True:
-                        # run until next progress event
-                        progress = pool.spawn(self.__next, iterator).wait()
-
-                        # raise StopIteration if return is of this type
-                        if isinstance(progress, StopIteration):
-                            raise progress
-
-                        # execute progress function
-                        if progress_fun is not None:
-                            if isinstance(progress, tuple):
-                                progress = progress_fun(*progress)
-                            else:
-                                progress = progress_fun(progress)
-
-                        # execute progress listeners
-                        job.progress = progress
-                        job.updated = int(time())
-
-                        for callback in self.__progress_listeners:
-                            callback(job)
-                except StopIteration as stop_iteration_exception:
-                    result = stop_iteration_exception.value
-
-            # update progress
-            job.progress = 1
-            job.updated = int(time())
-
-            for callback in self.__progress_listeners:
-                callback(job)
-
-            # execute result function
-            if result_fun is not None:
-                if isinstance(result, tuple):
-                    result_fun(*result)
-                else:
-                    result_fun(result)
-
-            # execute event
-            if result_event is not None:
-                result_event.send(result)
+            try:
+                generator = pool.spawn(executable, *args, **kwargs).wait()
+                result = generator
+
+                if isinstance(generator, GeneratorType):
+                    iterator = iter(generator)
+
+                    try:
+                        while True:
+                            # run until next progress event
+                            progress = pool.spawn(self.__next, iterator).wait()
+
+                            # raise StopIteration if return is of this type
+                            if isinstance(progress, StopIteration):
+                                raise progress
+
+                            # execute progress function
+                            if progress_fun is not None:
+                                if isinstance(progress, tuple):
+                                    progress = progress_fun(*progress)
+                                else:
+                                    progress = progress_fun(progress)
+
+                            # execute progress listeners
+                            job.progress = progress
+                            job.updated = int(time())
+
+                            for callback in self.__progress_listeners:
+                                callback(job)
+                    except StopIteration as stop_iteration_exception:
+                        result = stop_iteration_exception.value
+
+                # update progress
+                job.progress = 1
+                job.updated = int(time())
+
+                for callback in self.__progress_listeners:
+                    callback(job)
+
+                # execute result function
+                if result_fun is not None:
+                    if isinstance(result, tuple):
+                        result_fun(*result)
+                    else:
+                        result_fun(result)
+
+                # execute event
+                if result_event is not None:
+                    result_event.send(result)
+
+            # save exceptions to show in ui
+            except Exception as e:
+                job.exception = f'{type(e).__name__} ({str(e)})'
 
             # remove from group dict
             if group is not None:

+ 7 - 0
webui/src/components/window/job-window.vue

@@ -11,6 +11,8 @@
       <div class="subtitle">{{ job.type }}</div>
       <div class="title">{{ job.name }}</div>
 
+      <div v-if="job.exception" class="error">{{ job.exception }}</div>
+
       <progress-bar v-if="!job.finished"
                     :progress="job.progress"/>
     </div>
@@ -83,6 +85,11 @@ export default {
   font-size: 90%;
 }
 
+.error {
+  color: #FF1111;
+  font-size: 80%;
+}
+
 .progress-bar {
   height: 0.7rem;
   border-color: whitesmoke;

+ 9 - 1
webui/src/components/window/top-navigation-bar.vue

@@ -15,7 +15,12 @@
     </div>
 
     <div class="jobs" :class="{colored: show}" @click="showJobs">
-      {{ runningJobCount }} {{ runningJobCount === 1 ? 'job' : 'jobs' }} running
+      <template v-if="failedJobCount > 0">
+        {{ failedJobCount }} {{ failedJobCount === 1 ? 'job' : 'jobs' }} failed
+      </template>
+      <template v-else>
+        {{ runningJobCount }} {{ runningJobCount === 1 ? 'job' : 'jobs' }} running
+      </template>
     </div>
 
     <job-window v-if="show"
@@ -76,6 +81,9 @@ export default {
     },
     runningJobCount: function () {
       return this.activeJobs.filter(j => !j.finished).length;
+    },
+    failedJobCount: function () {
+      return this.activeJobs.filter(j => j.exception).length;
     }
   },
   methods: {