Commit b6e0d7c2 authored by Kento HASEGAWA's avatar Kento HASEGAWA

Add support for cancellation of a problem or request in each solver

parent ffd55d63
...@@ -147,6 +147,9 @@ class Host(object): ...@@ -147,6 +147,9 @@ class Host(object):
elif cmd == 'stop': elif cmd == 'stop':
self.worker_manager.request_stop() self.worker_manager.request_stop()
return {} return {}
elif cmd == 'cancel':
self.worker_manager.request_cancel(params)
return {'status': 'canceled'}
elif cmd == 'worker/status': elif cmd == 'worker/status':
self.worker_manager.update_status(params['address'], params['status']) self.worker_manager.update_status(params['address'], params['status'])
return {'status': 'updated'} return {'status': 'updated'}
...@@ -232,6 +235,9 @@ class WorkerManager(object): ...@@ -232,6 +235,9 @@ class WorkerManager(object):
def request_stop(self): def request_stop(self):
self.broadcast('stop', {}) self.broadcast('stop', {})
def request_cancel(self, params):
self.broadcast('cancel', params)
def broadcast(self, cmd, params, solvers=None): def broadcast(self, cmd, params, solvers=None):
......
...@@ -19,9 +19,10 @@ class Solver(object): ...@@ -19,9 +19,10 @@ class Solver(object):
self.solver = importlib.import_module(f"solvers.{config['solver']}") self.solver = importlib.import_module(f"solvers.{config['solver']}")
self.queue = OrderedDict() self.queue = OrderedDict()
self.solving = None
self.status = None self.status = None
# self.thread = None
self.thread = threading.Thread(name='solver', target=self.solver_thread, daemon=True) self.thread = threading.Thread(name='solver', target=self.solver_thread, daemon=True)
self.thread.start() self.thread.start()
...@@ -43,14 +44,15 @@ class Solver(object): ...@@ -43,14 +44,15 @@ class Solver(object):
if len(self.queue) > 0: if len(self.queue) > 0:
print("I: Solver started") print("I: Solver started")
_, params = self.queue.popitem(last=False) _, params = self.queue.popitem(last=False)
# self.status = f'Running ({len(self.queue)} in queue)' self.solving = params
self.set_status(f'Running ({len(self.queue)} in queue)') self.set_status(f'Running ({len(self.queue)} in queue)')
self.solve(params) try:
# self.status = 'Ready' self.solve(params)
except Exception as e:
print("E: An error has occurred in the solver thread")
self.solving = None
self.set_status('Ready') self.set_status('Ready')
else: else:
# self.status = 'Ready'
self.set_status('Ready')
time.sleep(0.5) time.sleep(0.5)
def solve(self, params): def solve(self, params):
...@@ -65,7 +67,7 @@ class Solver(object): ...@@ -65,7 +67,7 @@ class Solver(object):
solution['elapsed_time'] = elapsed_time solution['elapsed_time'] = elapsed_time
self.submit_solution(params, solution) self.submit_solution(params, solution)
# self.thread = None
return True return True
def post(self, path, data): def post(self, path, data):
...@@ -94,16 +96,35 @@ class Solver(object): ...@@ -94,16 +96,35 @@ class Solver(object):
print("I: Problem queued") print("I: Problem queued")
_id = params['request_id'] _id = params['request_id']
self.queue[_id] = params self.queue[_id] = params
# self.status = f'Running ({len(self.queue)} in queue)'
self.set_status(f'Running ({len(self.queue)} in queue)') self.set_status(f'Running ({len(self.queue)} in queue)')
return {'status': self.status} return {'status': self.status}
def stop_solver(self): def stop_solver(self):
if self.thread is not None: # if self.thread is not None:
self.solver.stop() # self.solver.stop()
self.solver.stop()
return {'status': self.status} return {'status': self.status}
def cancel_queue(self, params):
if 'request_id' in params:
request_id = params['request']
for k, v in self.queue.items():
if k == request_id:
self.queue.pop(k, None)
if self.solving['request_id'] == request_id:
self.solver.stop()()
elif 'problem' in params:
problem_name = params['problem']
for k, v in self.queue.items():
if v['name'] == problem_name:
self.queue.pop(k, None)
if self.solving['name'] == problem_name:
self.solver.stop()()
return {'status': 'canceled'}
def call_api(self, method, cmd, params): def call_api(self, method, cmd, params):
if cmd == 'role': if cmd == 'role':
...@@ -112,6 +133,8 @@ class Solver(object): ...@@ -112,6 +133,8 @@ class Solver(object):
return self.start_solver(params) return self.start_solver(params)
elif cmd == 'stop': elif cmd == 'stop':
return self.stop_solver() return self.stop_solver()
elif cmd == 'cancel':
return self.cancel_queue(params)
elif cmd == 'status': elif cmd == 'status':
return {'status': self.status} return {'status': self.status}
else: else:
......
...@@ -30,6 +30,10 @@ class StatusView { ...@@ -30,6 +30,10 @@ class StatusView {
_this.start_solver(); _this.start_solver();
}); });
_this.container.find('.cancel-button').click(()=>{
_this.cancel_problem();
});
_this.container.find('.save-button').click(()=>{ _this.container.find('.save-button').click(()=>{
_this.save_solution(); _this.save_solution();
_this.fire('refresh'); _this.fire('refresh');
...@@ -112,6 +116,28 @@ class StatusView { ...@@ -112,6 +116,28 @@ class StatusView {
}); });
} }
cancel_problem(){
var _this = this;
var _button = _this.container.find('.cancel-button')
_button.html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span><span class="sr-only">Loading...</span>');
_button.prop('disabled', 'disabled');
$.ajax({
type: "POST",
dataType: "json",
url: "/api/cancel",
data: JSON.stringify({
"problem": _this.problem_key,
}),
contentType: 'application/json'
}).done((d) => {
_button.prop('disabled', false);
_button.text('Cancel');
console.log(d);
});
}
// 強制停止 // 強制停止
stop_solver(){ stop_solver(){
var _this = this; var _this = this;
......
<div> <div>
<h4 class='inline-heading' id='problem-status-title'>{{problem.name}}</h4> <h4 class='inline-heading' id='problem-status-title'>{{problem.name}}</h4>
<a href="/viewer#{{problem.name}}" target="_blank">Viewer</a>
{#% # if localmode %#} {#% # if localmode %#}
<button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{problem.name}}">Start</button> <button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{problem.name}}">Start</button>
<!-- <button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button> --> <button class="btn btn-danger btn-lg cancel-button" type="button" data-qname="{{problem.name}}">Cancel</button>
<button class="btn btn-info btn-lg save-button" type="button" data-qname="{{problem.name}}">Save</button> <button class="btn btn-info btn-lg save-button" type="button" data-qname="{{problem.name}}">Save</button>
<button class="btn btn-success btn-lg submit-button" type="button" data-qname="{{problem.name}}">Up</button> <button class="btn btn-success btn-lg submit-button" type="button" data-qname="{{problem.name}}">Up</button>
{#% else %#} {#% else %#}
<!-- [View Only] --> <!-- [View Only] -->
<a class="btn btn-outline-success btn-lg" href="/viewer#{{problem.name}}" role="button" target='_blank'>Viewer</a>
{#% endif %#} {#% endif %#}
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment