From 3dfe0e87226fb5babb3b4a3ab7097fc33b9fb57d Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sat, 2 Nov 2019 20:54:19 -0700 Subject: [PATCH] Allow thrimshim to safely cancel a job while it is cutting This differs from the existing reset row by only suceeding if the upload is not in finalizing. We also make some changes to cutter to handle this situation gracefully. --- cutter/cutter/main.py | 15 +++++++++++++-- thrimshim/thrimshim/main.py | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/cutter/cutter/main.py b/cutter/cutter/main.py index 65dd889..6fee313 100644 --- a/cutter/cutter/main.py +++ b/cutter/cutter/main.py @@ -86,6 +86,10 @@ class CandidateGone(Exception): """Exception indicating a job candidate is no longer available""" +class JobCancelled(Exception): + """Exception indicating a job was cancelled by an operator after we had claimed it.""" + + class Cutter(object): NO_CANDIDATES_RETRY_INTERVAL = 1 ERROR_RETRY_INTERVAL = 5 @@ -125,7 +129,10 @@ class Cutter(object): self.claim_job(job) except CandidateGone: continue - self.cut_job(job) + try: + self.cut_job(job) + except JobCancelled: + self.logger.info("Job was cancelled while we were cutting it: {}".format(format_job(job))) def refresh_conn(self): """After errors, we reconnect in case the error was connection-related.""" @@ -332,6 +339,10 @@ class Cutter(object): )) result = query(self.conn, built_query, id=job.id, name=self.name, **kwargs) if result.rowcount != 1: + # If we hadn't yet set finalizing, then this means an operator cancelled the job + # while we were cutting it. This isn't a problem. + if not finalize_begun: + raise JobCancelled() raise JobConsistencyError("No job with id {} and uploader {} when setting: {}".format( job.id, self.name, ", ".join("{} = {!r}".format(k, v) for k, v in kwargs.items()) )) @@ -372,7 +383,7 @@ class Cutter(object): tags=self.tags + [job.category, job.sheet_name], data=upload_wrapper(), ) - except (JobConsistencyError, UploadError): + except (JobConsistencyError, JobCancelled, UploadError): raise # this ensures these aren't not caught in the except Exception block except Exception as ex: self.refresh_conn() diff --git a/thrimshim/thrimshim/main.py b/thrimshim/thrimshim/main.py index 41d5b2f..9eb188a 100644 --- a/thrimshim/thrimshim/main.py +++ b/thrimshim/thrimshim/main.py @@ -300,15 +300,24 @@ def manual_link(ident, editor=None): @request_stats @authenticate def reset_row(ident, editor=None): - """Clear state and video_link columns and reset state to 'UNEDITED'.""" + """Clear state and video_link columns and reset state to 'UNEDITED'. + If force is 'true', it will do so regardless of current state. + Otherwise, it will only do so if we know no video has been uploaded + (state is UNEDITED, EDITED or CLAIMED) + """ + force = (flask.request.args.get('force', '').lower() == "true") conn = app.db_manager.get_conn() - results = database.query(conn, """ + query = """ UPDATE events SET state='UNEDITED', error = NULL, video_id = NULL, video_link = NULL, uploader = NULL, editor = NULL, edit_time = NULL, upload_time = NULL - WHERE id = %s""", ident) + WHERE id = %s{} + """.format( + "" if force else " AND state IN ('UNEDITED', 'EDITED', 'CLAIMED')", + ) + results = database.query(conn, query, ident) if results.rowcount != 1: - return 'Row id = {} not found'.format(ident), 404 + return 'Row id = {} not found or not in cancellable state'.format(ident), 404 logging.info("Row {} reset to 'UNEDITED'".format(ident)) return ''