diff --git a/db_schema.sql b/db_schema.sql index e9e0a1175f14e764b3b1b439dd6f6a80b0c50a79..67227e42d561ea7d4b6b821210f6e833aa2ee801 100644 --- a/db_schema.sql +++ b/db_schema.sql @@ -296,7 +296,8 @@ CREATE TABLE IF NOT EXISTS `jobs` ( `last_ping` datetime NOT NULL DEFAULT '', `worker` text DEFAULT NULL, `data` text NOT NULL DEFAULT '{}', - `status` text NOT NULL DEFAULT '{}' + `status` text NOT NULL DEFAULT '{}', + `canceled` INTEGER DEFAULT 0 ); CREATE TABLE IF NOT EXISTS `responsible` ( diff --git a/jobs.py b/jobs.py index 86b5519436c336400aff9b16f1503e759399eb81..9fb807088d39d13a397fc016ef7b66ac841d4a00 100644 --- a/jobs.py +++ b/jobs.py @@ -18,9 +18,16 @@ def job_handler(*types, state='finished'): def schedule_job(jobtype, data=None, priority=0, queue="default"): if not data: data = {} - modify('INSERT INTO jobs (type, priority, queue, data, time_created) VALUES (?, ?, ?, ?, ?)', + return modify('INSERT INTO jobs (type, priority, queue, data, time_created) VALUES (?, ?, ?, ?, ?)', jobtype, priority, queue, json.dumps(data, default=date_json_handler), datetime.now()) +def cancel_job(job_id): + modify('UPDATE jobs SET state = "deleted" WHERE id = ? AND state = "ready"', job_id) + modify('UPDATE jobs SET canceled = 1 WHERE id = ?', job_id) + +def restart_job(job_id): + modify('UPDATE jobs SET state = "ready" WHERE id = ? AND state = "failed" AND NOT canceled', job_id) + @app.route('/internal/jobs/overview') @register_navbar('Jobs', iconlib='fa', icon='suitcase') @mod_required @@ -61,12 +68,12 @@ def jobs_action(action, jobid=None): query('UPDATE jobs SET state="deleted" WHERE state = "failed" AND (id = ? OR ? IS NULL)', jobid, jobid) elif action == 'retry_failed': query('UPDATE jobs SET state="ready" WHERE state = "failed" AND (id = ? OR ? IS NULL)', jobid, jobid) - elif action == 'copy': - if jobid: - query("INSERT INTO jobs SELECT NULL, type, priority, queue, 'ready', '', '' , ?, '', NULL, data, '{}' FROM jobs where ID=?;", datetime.now(), jobid) - elif action == 'delete': - if jobid: - query('UPDATE jobs SET state="deleted" WHERE id = ?', jobid) + elif action == 'copy' and jobid: + query("INSERT INTO jobs SELECT NULL, type, priority, queue, 'ready', '', '' , ?, '', NULL, data, '{}' FROM jobs where ID=?;", datetime.now(), jobid) + elif action == 'delete' and jobid: + query('UPDATE jobs SET state="deleted" WHERE id = ?', jobid) + elif action == 'cancel' and jobid: + cancel_job(jobid) return redirect(request.values.get('ref', url_for('jobs_overview'))) def jobs_api_token_required(func): @@ -118,7 +125,10 @@ def jobs_ping(id): func(id, job['type'], json.loads(job['data']), state, json.loads(job['status'])) except Exception: traceback.print_exc() - return 'OK', 200 + if job['canceled']: + return 'Job canceled', 205 + else: + return 'OK', 200 @app.route('/internal/jobs/api/worker/<hostname>/schedule', methods=['POST']) @jobs_api_token_required diff --git a/server.py b/server.py index 1c536d032663ddd8d99a9f5de492750dfc8a40bc..b762ae168c636372c6d79789e27bcde4839bdebe 100644 --- a/server.py +++ b/server.py @@ -486,7 +486,7 @@ def dbstatus(): def date_json_handler(obj): return obj.isoformat() if hasattr(obj, 'isoformat') else obj -from jobs import job_handler, schedule_job +from jobs import job_handler, schedule_job, cancel_job, restart_job from edit import edit_handler import feeds import importer diff --git a/templates/jobs_overview.html b/templates/jobs_overview.html index 87aa4a070b58dfae214246fce93216f79f8fa1a2..2f099a445614be7094d49104c313f91d6f0b5a32 100644 --- a/templates/jobs_overview.html +++ b/templates/jobs_overview.html @@ -192,7 +192,7 @@ <td>{{i.priority}}</td> <td>{{i.worker}}</td> <td>{{i.last_ping}}</td> - <td>{{i.state}}</td> + <td>{{i.state}}{% if i.canceled %} (canceled) {% endif %}</td> <td>{{i.time_created}}</td> <td>{{i.time_finished}}</td> <td>{{i.time_scheduled}}</td> @@ -223,6 +223,12 @@ <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> </a> </li> + {% elif i.state == "running" %} + <li> + <a class="btn btn-default" {% if i.canceled %}disabled="disabled"{% endif %} href="{{url_for('jobs_action', action='cancel', jobid=i.id, ref=request.url)}}" title="Abbrechen" style="background-color: red;"> + <span class="glyphicon glyphicon-stop" aria-hidden="true"></span> + </a> + </li> {% endif %} {% endif %} </ul>