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.
pull/138/head
Mike Lang 5 years ago
parent b27e06d068
commit 3dfe0e8722

@ -86,6 +86,10 @@ class CandidateGone(Exception):
"""Exception indicating a job candidate is no longer available""" """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): class Cutter(object):
NO_CANDIDATES_RETRY_INTERVAL = 1 NO_CANDIDATES_RETRY_INTERVAL = 1
ERROR_RETRY_INTERVAL = 5 ERROR_RETRY_INTERVAL = 5
@ -125,7 +129,10 @@ class Cutter(object):
self.claim_job(job) self.claim_job(job)
except CandidateGone: except CandidateGone:
continue 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): def refresh_conn(self):
"""After errors, we reconnect in case the error was connection-related.""" """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) result = query(self.conn, built_query, id=job.id, name=self.name, **kwargs)
if result.rowcount != 1: 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( 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()) 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], tags=self.tags + [job.category, job.sheet_name],
data=upload_wrapper(), data=upload_wrapper(),
) )
except (JobConsistencyError, UploadError): except (JobConsistencyError, JobCancelled, UploadError):
raise # this ensures these aren't not caught in the except Exception block raise # this ensures these aren't not caught in the except Exception block
except Exception as ex: except Exception as ex:
self.refresh_conn() self.refresh_conn()

@ -300,15 +300,24 @@ def manual_link(ident, editor=None):
@request_stats @request_stats
@authenticate @authenticate
def reset_row(ident, editor=None): 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() conn = app.db_manager.get_conn()
results = database.query(conn, """ query = """
UPDATE events UPDATE events
SET state='UNEDITED', error = NULL, video_id = NULL, video_link = NULL, SET state='UNEDITED', error = NULL, video_id = NULL, video_link = NULL,
uploader = NULL, editor = NULL, edit_time = NULL, upload_time = 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: 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)) logging.info("Row {} reset to 'UNEDITED'".format(ident))
return '' return ''

Loading…
Cancel
Save