layerindex-web/templates/layerindex/task.html
Paul Eggleton d84bfd710d Allow stopping update task
For situations where the user launches a distro comparison update
process and then shortly afterwards realises it is operating with the
wrong configuration (or is otherwise broken) and is going to take a long
time to finish, add a button to the task page to stop the task. This was
tricky to get working, since the default behaviour of Celery's revoke()
would either terminate both the Celery task process along with the update
process (leaving us with no log saved to the database) or worse not even
kill the update process, depending on the signal sent. To avoid this,
send SIGUSR2, trap it in the task process and kill the child process,
returning gracefully. To make that possible I had to rewrite runcmd() to
use subprocess.Popen() instead of subprocess.check_call() as otherwise
we can't get the child's PID.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
2018-09-20 16:04:49 +12:00

124 lines
4.4 KiB
HTML

{% extends "base.html" %}
{% load i18n %}
{% load extrafilters %}
{% comment %}
layerindex-web - task page
Copyright (C) 2018 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
<!--
{% block title_append %} - task status{% endblock %}
-->
{% block content %}
{% autoescape on %}
<p>Task status for {{ update.task_id }} started by {{ update.triggered_by }} on {{ update.started }}<span id="task_status_fragment">{% if update.finished %} (finished in {{ update.started | timesince2:update.finished }}){% endif %}</span>:<span id="status-label" class="label {% if update.finished %}{% if update.retcode %}label-danger{% else %}label-success{% endif %}{% endif %} pull-right">{% if update.finished %}{% if update.retcode < 0 %}TERMINATED ({{ update.retcode }}){% elif update.retcode %}FAILED{% else %}SUCCEEDED{% endif %}{% endif %}</span></p>
<pre id="task_log" class="vertical-scroll">{{ update.log }}</pre>
{% if not update.finished %}
<div class="progress">
<div id="progressbar" class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
</div>
</div>
{% endif %}
{% if not update.finished %}
<button id="stopbutton" class="btn btn-danger pull-right">Stop</a>
{% endif %}
{% if update.comparisonrecipeupdate_set.exists %}
<h3>Updated comparison recipes</h3>
<ul>
{% for recipeupdate in update.comparisonrecipeupdate_set.all %}
<li><a href="{% url 'comparison_recipe' recipeupdate.recipe.id %}">{{ recipeupdate.recipe.pn }}</a> {% if recipeupdate.meta_updated and recipeupdate.link_updated %}(meta, link){% elif recipeupdate.link_updated %}(link){% elif recipeupdate.meta_updated %}(meta){% endif %}</li>
{% endfor %}
</ul>
{% endif %}
{% endautoescape %}
{% endblock %}
{% block footer %}
{% endblock %}
{% block scripts %}
<script>
var posn = 0;
var done = '0';
var duration = ''
var scrolling = true;
function updateLog() {
$.ajax({
url: '{{ log_url }}?start=' + posn,
success: function( data, code, xhr ) {
task_log = $("#task_log")
task_log.append(data);
if(scrolling) {
task_log.animate({ scrollTop: task_log.prop('scrollHeight') }, "slow");
}
posn += data.length
done = xhr.getResponseHeader('Task-Done')
duration = xhr.getResponseHeader('Task-Duration')
progress = parseInt(xhr.getResponseHeader('Task-Progress')) || 0;
if(progress) {
$('#progressbar').css('width', progress + '%').attr('aria-valuenow', progress);
$("#progressbar").html(progress + '%')
}
result = xhr.getResponseHeader('Task-Result');
if(result && result != 0) {
progress = 100
$('#progressbar').css('width', progress + '%').attr('aria-valuenow', progress);
if(result < 0) {
failstr = "TERMINATED (" + result + ")";
}
else {
failstr = "FAILED";
}
$("#progressbar").html(failstr);
$("#progressbar").removeClass('progress-bar-info').addClass('progress-bar-danger');
$("#status-label").html(failstr);
$("#status-label").addClass('label-danger');
}
else if(done == '1') {
$("#status-label").html('SUCCEEDED');
$("#status-label").addClass('label-success');
}
}
}).always(function () {
if(done == '1') {
$("#task_status_fragment").html(" (finished in " + duration + ")")
$("#stopbutton").hide()
}
else {
window.setTimeout(updateLog, 1000);
}
});
}
$("#task_log").scroll(function() {
scrolling = ($(this).scrollTop() + $(this).height() + 50 > $(this).prop('scrollHeight'))
});
$("#stopbutton").click(function() {
$.ajax({
url: "{% url 'task_stop' update.task_id %}"
});
});
$(document).ready(function() {
{% if not update.finished %}
updateLog();
{% endif %}
});
</script>
{% endblock %}