[Kimchi-devel] [PATCH] [Wok 1/2] Issue #122 - Make AsyncTask stoppable.
Aline Manera
alinefm at linux.vnet.ibm.com
Wed Aug 31 17:26:10 UTC 2016
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 at linux.vnet.ibm.com wrote:
>>> From: Paulo Vital <pvital at 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 at 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()
More information about the Kimchi-devel
mailing list