On 08/31/2016 02:22 PM, Paulo Ricardo Paz Vital wrote:
On Aug 31 01:51PM, Aline Manera wrote:
>
> On 08/30/2016 10:57 AM, pvital(a)linux.vnet.ibm.com wrote:
>> From: Paulo Vital <pvital(a)linux.vnet.ibm.com>
>>
>> This patch gives to user a way to 'stop' a Task that is still running by
setting
>> the Task status to "killed".
>>
>> Since an AsyncTask is basic a thread running in the system and this thread can
>> execute a pure Python method or a background command (by using run_command()
>> from wok.utils), the developer must pass to AsyncTask constructor a method to be
>> executed by the DELETE operation, called here as 'kill_cb'. If none
kill_cb is
>> passed, the task will not be able to stopped and an error message will be raised
>> to user if DELETE operation is executed. Otherwise, the kill_cb method will be
>> executed by kill() method (responsible to execute the DELETE operation) of
>> AsyncTask class and its status set to 'killed'.
>>
>> Signed-off-by: Paulo Vital <pvital(a)linux.vnet.ibm.com>
>> ---
>> docs/API/tasks.md | 2 ++
>> src/wok/asynctask.py | 18 +++++++++++++++++-
>> src/wok/i18n.py | 1 +
>> src/wok/model/tasks.py | 13 +++++++++++++
>> 4 files changed, 33 insertions(+), 1 deletion(-)
>>
>> diff --git a/docs/API/tasks.md b/docs/API/tasks.md
>> index e0c404f..2068f29 100644
>> --- a/docs/API/tasks.md
>> +++ b/docs/API/tasks.md
>> @@ -27,8 +27,10 @@ server.
>> * running: The task is running
>> * finished: The task has finished successfully
>> * failed: The task failed
>> + * killed: The task was killed by user
>> * message: Human-readable details about the Task status
>> * target_uri: Resource URI related to the Task
>> +* **DELETE**: Kill the Task, moving its status to 'killed'
>> * **POST**: *See Task Actions*
>>
>> **Actions (POST):**
>> diff --git a/src/wok/asynctask.py b/src/wok/asynctask.py
>> index b98ad9a..4a4ee32 100644
>> --- a/src/wok/asynctask.py
>> +++ b/src/wok/asynctask.py
>> @@ -26,6 +26,9 @@ import traceback
>> import uuid
>>
>>
>> +from wok.exception import OperationFailed
>> +
>> +
>> tasks_queue = {}
>>
>>
>> @@ -41,10 +44,11 @@ def clean_old_tasks():
>>
>>
>> class AsyncTask(object):
>> - def __init__(self, target_uri, fn, opaque=None):
>> + def __init__(self, target_uri, fn, opaque=None, kill_cb=None):
>> self.id = str(uuid.uuid1())
>> self.target_uri = target_uri
>> self.fn = fn
>> + self.kill_cb = kill_cb
>> self.status = 'running'
>> self.message = 'The request is being processing.'
>> self.timestamp = time.time()
>> @@ -79,3 +83,15 @@ class AsyncTask(object):
>> except KeyError:
>> msg = "There's no task_id %s in tasks_queue. Nothing
changed."
>> cherrypy.log.error_log.error(msg % self.id)
>> +
>> + def kill(self):
>> + if self.kill_cb is None:
>> + msg = 'There is no callback to execute DELETE operation.'
>> + raise OperationFailed('WOKASYNC0002E', {'err':
msg})
>> +
> It should be "InvalidOperation" exception.
OK!
/me never knows which exception is the best!!
>> + try:
>> + self.kill_cb()
>> + self.status = 'killed'
>> + self.message = 'Task killed by user.'
>> + except Exception, e:
>> + raise OperationFailed('WOKASYNC0002E', {'err':
e.message})
> I see you are using WOKASYNC0002E with a placeholder for 'err' but in both
> cases the error message is manually set in the code.
>
> msg = 'There is no callback to execute DELETE operation.'
> self.message = 'Task killed by user.'
>
> I'd suggest to create 2 different error codes, one for each case above, so
> the entire message can be translated.
> Otherwise, the error message will keep in English and we can translate it to
> the language the user sets.
>
Here I'm raising the exception message. The self.message is the AsyncTask
message field and will not be used here.
I got your point, so I'll create one specific message to be used to
msg = 'There is no callback to execute DELETE operation.' and let
WOKASYNC0002E as is, because the idea is inform the exception error.
Ok.
About the message:
self.message = 'Task killed by user.'
Maybe it is better to fill it will the exception raised too.
I am afraid of the UI uses this message someway and it will not be
translated.
self.message = e.message
>> diff --git a/src/wok/i18n.py b/src/wok/i18n.py
>> index ade2ae9..937477f 100644
>> --- a/src/wok/i18n.py
>> +++ b/src/wok/i18n.py
>> @@ -34,6 +34,7 @@ messages = {
>> "WOKAPI0009E": _("You don't have permission to perform
this operation."),
>>
>> "WOKASYNC0001E": _("Unable to find task id: %(id)s"),
>> + "WOKASYNC0002E": _("Unable to kill task due error:
%(err)s"),
>> "WOKASYNC0003E": _("Timeout of %(seconds)s seconds expired
while running task '%(task)s."),
>>
>> "WOKAUTH0001E": _("Authentication failed for user
'%(username)s'. [Error code: %(code)s]"),
>> diff --git a/src/wok/model/tasks.py b/src/wok/model/tasks.py
>> index 6a2b4bf..8ae1ce4 100644
>> --- a/src/wok/model/tasks.py
>> +++ b/src/wok/model/tasks.py
>> @@ -68,3 +68,16 @@ class TaskModel(object):
>>
>> raise TimeoutExpired('WOKASYNC0003E', {'seconds':
timeout,
>> 'task':
task.target_uri})
>> +
>> + def delete(self, id):
>> + """
>> + 'Stops' an AsyncTask, by executing the kill callback provided by
user
>> + when created the task. Task's status will be changed to
'killed'.
>> + """
>> + try:
>> + task = tasks_queue[id]
>> + except KeyError:
>> + raise NotFoundError("WOKASYNC0001E", {'id': id})
>> +
>> + if task.status is 'running':
>> + task.kill()