Merge pull request #138 from ekimekim/mike/thrimbletrimmer/cancel-upload

Allow thrimshim to safely cancel a job while it is cutting
pull/144/head
Mike Lang 5 years ago committed by GitHub
commit 8d3c863a49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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
try:
self.cut_job(job) 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()

@ -98,7 +98,8 @@
<a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> | <a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> |
<a href="/thrimbletrimmer/stream.html">Go to Re-stream View</a> | <a href="/thrimbletrimmer/stream.html">Go to Re-stream View</a> |
<a id="ManualLinkButton" href="JavaScript:toggleHiddenPane('ManualLinkPane');">Manual Link</a> | <a id="ManualLinkButton" href="JavaScript:toggleHiddenPane('ManualLinkPane');">Manual Link</a> |
<a id="ResetButton" href="JavaScript:thrimbletrimmerResetLink();">Reset Edits</a> <a id="CancelButton" href="JavaScript:thrimbletrimmerResetLink(false);">Cancel Upload</a> |
<a id="ResetButton" href="JavaScript:thrimbletrimmerResetLink(true);">Force Reset Row</a>
<a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a> <a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a>
<a id="UltrawideButton" style="float:right;margin-right:10px;" href="JavaScript:toggleUltrawide();">Ultrawide</a> <a id="UltrawideButton" style="float:right;margin-right:10px;" href="JavaScript:toggleUltrawide();">Ultrawide</a>
<br/> <br/>

@ -314,9 +314,9 @@ thrimbletrimmerManualLink = function() {
})); }));
}; };
thrimbletrimmerResetLink = function() { thrimbletrimmerResetLink = function(force) {
var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1]; var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
if(!confirm( if(force && !confirm(
'Are you sure you want to reset this event? ' + 'Are you sure you want to reset this event? ' +
'This will set the row back to UNEDITED and forget about any video that already may exist. ' + 'This will set the row back to UNEDITED and forget about any video that already may exist. ' +
'It is intended as a last-ditch command to clear a malfunctioning cutter, ' + 'It is intended as a last-ditch command to clear a malfunctioning cutter, ' +
@ -326,11 +326,12 @@ thrimbletrimmerResetLink = function() {
return; return;
} }
document.getElementById("ResetButton").disabled = true; document.getElementById("ResetButton").disabled = true;
document.getElementById("CancelButton").disabled = true;
var body = {} var body = {}
if (!!user) { if (!!user) {
body.token = user.getAuthResponse().id_token; body.token = user.getAuthResponse().id_token;
} }
fetch("/thrimshim/reset/"+rowId, { fetch("/thrimshim/reset/"+rowId + "?force=" + force, {
method: 'POST', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
@ -344,8 +345,9 @@ thrimbletrimmerResetLink = function() {
console.log(error); console.log(error);
alert(error); alert(error);
document.getElementById("ResetButton").disabled = false; document.getElementById("ResetButton").disabled = false;
document.getElementById("CancelButton").disabled = true;
} else { } else {
alert("Row has been reset. Reloading..."); alert("Row has been " + ((force) ? "reset" : "cancelled") +". Reloading...");
setTimeout(() => { window.location.reload(); }, 500); setTimeout(() => { window.location.reload(); }, 500);
} }
})); }));

@ -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