about summary refs log tree commit diff
path: root/uploader/background_jobs.py
diff options
context:
space:
mode:
Diffstat (limited to 'uploader/background_jobs.py')
-rw-r--r--uploader/background_jobs.py107
1 files changed, 94 insertions, 13 deletions
diff --git a/uploader/background_jobs.py b/uploader/background_jobs.py
index ac47ff2..09ea0c0 100644
--- a/uploader/background_jobs.py
+++ b/uploader/background_jobs.py
@@ -1,14 +1,86 @@
 import uuid
+import logging
+import importlib
+from typing import Callable
+from functools import partial
 
-from flask import request, Blueprint, render_template, current_app as app
+from flask import (
+    request,
+    url_for,
+    redirect,
+    Response,
+    Blueprint,
+    render_template,
+    current_app as app)
 
 from gn_libs import jobs
-from gn_libs.jobs.jobs import JobNotFound
 from gn_libs import sqlite3
+from gn_libs.jobs.jobs import JobNotFound
 
 from uploader.authorisation import require_login
 
 background_jobs_bp = Blueprint("background-jobs", __name__)
+HandlerType = Callable[[dict], Response]
+
+
+def __default_error_handler__(job: dict) -> Response:
+    return redirect(url_for("background-jobs.job_error", job_id=job["job_id"]))
+
+def register_handlers(
+        job_type: str,
+        success_handler: HandlerType,
+        error_handler: HandlerType = __default_error_handler__
+) -> str:
+    if not bool(app.config.get("background-jobs")):
+        app.config["background-jobs"] = {}
+
+    if not bool(app.config["background-jobs"].get(job_type)):
+        app.config["background-jobs"][job_type] = {
+            "success": success_handler,
+            "error": error_handler
+        }
+
+    return job_type
+
+
+def register_job_handlers(job: str):
+    """Related to register handlers above."""
+    def __load_handler__(absolute_function_path):
+        _parts = absolute_function_path.split(".")
+        app.logger.debug("THE PARTS ARE: %s", _parts)
+        assert len(_parts) > 1, f"Invalid path: {absolute_function_path}"
+        function = _parts[-1]
+        module = importlib.import_module(f".{_parts[-2]}",
+                                         package=".".join(_parts[0:-2]))
+        return getattr(module, _parts[-1])
+
+    metadata = job["metadata"]
+    if metadata["success_handler"]:
+        success_handler = __load_handler__(metadata["success_handler"])
+        try:
+            error_handler = __load_handler__(metadata["error_handler"])
+        except Exception as _exc:
+            error_handler = __default_error_handler__
+        register_handlers(metadata["job-type"], success_handler, error_handler)
+
+
+def handler(job: dict, handler_type: str) -> HandlerType:
+    """Fetch a handler for the job."""
+    _job_type = job["metadata"]["job-type"]
+    _handler = app.config.get(
+        "background-jobs", {}
+    ).get(
+        _job_type, {}
+    ).get(handler_type)
+    if bool(_handler):
+        return _handler(job)
+    raise Exception(
+        f"No '{handler_type}' handler registered for job type: {_job_type}")
+
+
+error_handler = partial(handler, handler_type="error")
+success_handler = partial(handler, handler_type="success")
+
 
 @background_jobs_bp.route("/status/<uuid:job_id>")
 @require_login
@@ -17,19 +89,28 @@ def job_status(job_id: uuid.UUID):
     with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
         try:
             job = jobs.job(conn, job_id, fulldetails=True)
-            stdout = ""
-            stderr = ""
-            # with (open(job["metadata"]["stdout-file"], encoding="utf-8") as stdout_file,
-            #       open(job["metadata"]["stderr-file"], encoding="utf-8") as stderr_file):
-            #     stdout = stdout_file.read()
-            #     stderr = stderr_file.read()
+            status = job["metadata"]["status"]
 
-            return render_template(
-                f"jobs/job-status.html",
-                job=job,
-                stdout=stdout,
-                stderr=stderr)
+            register_job_handlers(job)
+            if status == "error":
+                return error_handler(job)
+
+            if status == "completed":
+                return success_handler(job)
+
+            return render_template(f"jobs/job-status.html", job=job)
         except JobNotFound as jnf:
             return render_template(
                 "jobs/job-not-found.html",
                 job_id=job_id)
+
+
+@background_jobs_bp.route("/error/<uuid:job_id>")
+@require_login
+def job_error(job_id: uuid.UUID):
+    with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
+        try:
+            job = jobs.job(conn, job_id, fulldetails=True)
+            return render_template("jobs/job-error.html", job=job)
+        except JobNotFound as jnf:
+            return render_template("jobs/job-not-found.html", job_id=job_id)