Coverage for gws-app/gws/base/job/__init__.py: 100%
1 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""Background jobs.
3Runs long tasks, such as printing or exporting, outside of the web request
4that started them. The client starts a job, receives its uid and polls its
5status until the job is complete, then fetches the result.
7Submodules
8----------
10- ``manager`` - the job manager (``root.app.jobMgr``). It stores jobs in a
11 SQLite database, schedules and runs them and handles status and cancel
12 requests.
13- ``worker`` - the base class for job workers, with access to the job record
14 for progress updates and cancellation checks.
16Jobs
17----
19A job record (``gws.Job``) holds the user, the worker class, the state,
20progress counters, a payload for the worker and the result. Records live in
21``jobs.<version>.sqlite`` in the misc directory, so that all server processes
22see the same jobs.
24A job goes through the states ``open`` (created), ``running`` and then
25``complete``, ``error`` or ``cancel``. ``schedule_job`` passes the job to the
26uWSGI spooler if it is available, otherwise the job runs at once in the
27current process. ``run_job`` marks the job as running atomically, so a job runs
28only once, imports the worker class and calls its ``run`` class method. An
29exception in the worker puts the job into the ``error`` state.
31Workers
32-------
34A worker is a class with a ``run(root, job)`` class method, usually a subclass
35of ``worker.Object``. While working, it reports progress with ``update_job``
36and finally stores the result. ``get_job`` and ``update_job`` raise
37``gws.JobTerminated`` when the job is no longer running, for example because
38it was cancelled, which ends the worker.
40Jobs belong to the user who created them; status, cancel and result requests
41from other users are answered with ``gws.NotFoundError``.
43Example::
45 class MyWorker(gws.base.job.worker.Object):
46 @classmethod
47 def run(cls, root, job):
48 w = cls(root, job.user, job)
49 w.work(job.payload)
51 def work(self, payload):
52 self.update_job(numSteps=len(payload['items']))
53 for n, item in enumerate(payload['items'], 1):
54 ...
55 self.update_job(step=n)
56 self.update_job(state=gws.JobState.complete, result={'count': n})
58 mgr = root.app.jobMgr
59 job = mgr.create_job(MyWorker, user, payload={'items': [...]})
60 job = mgr.schedule_job(job)
61 return mgr.job_status_response(job)
62"""
64from . import manager, worker