diff --git a/web/app/jobs/tasks.py b/web/app/jobs/tasks.py index e17bf5b413eb04c9a499a5ebf54aa8ac37cd7cfe..0daec41654a92fafd4c613a159dae167cc8c9ba8 100644 --- a/web/app/jobs/tasks.py +++ b/web/app/jobs/tasks.py @@ -1,9 +1,5 @@ -from time import sleep -from .. import db, logger from ..decorators import background from ..models import Job -import os -import shutil @background @@ -12,20 +8,7 @@ def delete_job(job_id, *args, **kwargs): with app.app_context(): job = Job.query.get(job_id) if job is None: - return - if job.status not in ['complete', 'failed']: - job.status = 'canceling' - db.session.commit() - while job.status != 'canceled': - # In case the daemon handled a job in any way - if job.status != 'canceling': - job.status = 'canceling' - db.session.commit() - sleep(1) - db.session.refresh(job) - path = os.path.join(app.config['NOPAQUE_STORAGE'], str(job.user_id), - 'jobs', str(job.id)) - shutil.rmtree(path, ignore_errors=True) + raise Exception('Could not find job with id {}'.format(job_id)) job.delete() @@ -35,16 +18,5 @@ def restart_job(job_id, *args, **kwargs): with app.app_context(): job = Job.query.get(job_id) if job is None: - logger.warning('Job not found') - return - if job.status != 'failed': - logger.warning('Job not failed') - return - logger.warning('Restarted') - job_dir = os.path.join(app.config['NOPAQUE_STORAGE'], - str(job.user_id), - 'jobs', - str(job.id)) - shutil.rmtree(os.path.join(job_dir, 'output'), ignore_errors=True) - shutil.rmtree(os.path.join(job_dir, 'pyflow.data'), ignore_errors=True) + raise Exception('Could not find job with id {}'.format(job_id)) job.restart() diff --git a/web/app/jobs/views.py b/web/app/jobs/views.py index 16b6756d0acdff6deb5727e77d666db2a28d7ecc..ffc17dd9b9981cabea81f8c978de784bb02754e0 100644 --- a/web/app/jobs/views.py +++ b/web/app/jobs/views.py @@ -56,7 +56,7 @@ def download_job_input(job_id, job_input_id): def restart(job_id): job = Job.query.get_or_404(job_id) if job.status != 'failed': - flash('Job can not be restarted!', 'job') + flash('Could not restart job: status is not "failed"', 'error') else: tasks.restart_job(job_id) flash('Job has been restarted!', 'job') diff --git a/web/app/models.py b/web/app/models.py index e2cf09fb68d73dc579f06fca71ba49d561ac4b96..538322d9719f801da9e6503323657613fc75da24 100644 --- a/web/app/models.py +++ b/web/app/models.py @@ -2,9 +2,12 @@ from datetime import datetime from flask import current_app from flask_login import UserMixin, AnonymousUserMixin from itsdangerous import BadSignature, TimedJSONWebSignatureSerializer +from time import sleep from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.utils import secure_filename from . import db, login_manager +import os +import shutil class Permission: @@ -364,7 +367,21 @@ class Job(db.Model): ''' Delete the job and its inputs and results from the database. ''' - + if self.status not in ['complete', 'failed']: + self.status = 'canceling' + db.session.commit() + while self.status != 'canceled': + # In case the daemon handled a job in any way + if self.status != 'canceling': + self.status = 'canceling' + db.session.commit() + sleep(1) + db.session.refresh(self) + job_dir = os.path.join(current_app.config['NOPAQUE_STORAGE'], + str(self.user_id), + 'jobs', + str(self.id)) + shutil.rmtree(job_dir, ignore_errors=True) db.session.delete(self) db.session.commit() @@ -374,7 +391,13 @@ class Job(db.Model): ''' if self.status != 'failed': - return + raise Exception('Could not restart job: status is not "failed"') + job_dir = os.path.join(current_app.config['NOPAQUE_STORAGE'], + str(self.user_id), + 'jobs', + str(self.id)) + shutil.rmtree(os.path.join(job_dir, 'output'), ignore_errors=True) + shutil.rmtree(os.path.join(job_dir, 'pyflow.data'), ignore_errors=True) self.end_date = None self.status = 'submitted' db.session.commit() diff --git a/web/app/templates/jobs/job.html.j2 b/web/app/templates/jobs/job.html.j2 index 50d8798038bad98c585d34de5de6fb2e83ee2df8..3c12a70ff95b23c3730fc94c51288af9e4dc4fce 100644 --- a/web/app/templates/jobs/job.html.j2 +++ b/web/app/templates/jobs/job.html.j2 @@ -71,7 +71,10 @@ </div> </div> <div class="card-action right-align"> - <a href="#" class="btn disabled waves-effect waves-light"><i class="material-icons left">settings</i>Export Parameters</a> + {% if current_user.is_administrator() and job.status == 'failed' %} + <a href="{{ url_for('jobs.restart', job_id=job.id) }}" class="btn waves-effect waves-light"><i class="material-icons left">repeat</i>Restart</a> + {% endif %} + <!-- <a href="#" class="btn disabled waves-effect waves-light"><i class="material-icons left">settings</i>Export Parameters</a> --> <a data-target="delete-job-modal" class="waves-effect waves-light btn red modal-trigger"><i class="material-icons left">delete</i>Delete</a> </div> </div>