[Checkins] SVN: lovely.remotetask/trunk/ merge of branch
adamg-startlater
Adam Groszer
agroszer at gmail.com
Tue Jan 29 09:40:08 EST 2008
Log message for revision 83297:
merge of branch adamg-startlater
- Some bugs smashed, improved tests.
- Added ``startLater`` to ``TaskService.add``. See startlater.txt for more info.
This facilitates to separate jobb add and start timepoints. (Not cron-like)
Changed:
U lovely.remotetask/trunk/CHANGES.txt
U lovely.remotetask/trunk/src/lovely/remotetask/README.txt
U lovely.remotetask/trunk/src/lovely/remotetask/browser/README.txt
U lovely.remotetask/trunk/src/lovely/remotetask/interfaces.py
U lovely.remotetask/trunk/src/lovely/remotetask/service.py
A lovely.remotetask/trunk/src/lovely/remotetask/startlater.txt
U lovely.remotetask/trunk/src/lovely/remotetask/testing.py
U lovely.remotetask/trunk/src/lovely/remotetask/tests.py
-=-
Modified: lovely.remotetask/trunk/CHANGES.txt
===================================================================
--- lovely.remotetask/trunk/CHANGES.txt 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/CHANGES.txt 2008-01-29 14:40:06 UTC (rev 83297)
@@ -2,6 +2,14 @@
Changes for lovely.remotetask
=============================
+2008/01/28 (new):
+=================
+
+- Some bugs smashed, improved tests.
+
+- Added ``startLater`` to ``TaskService.add``. See startlater.txt for more info.
+ This facilitates to separate jobb add and start timepoints. (Not cron-like)
+
2007/12/?? (new):
=================
@@ -114,4 +122,3 @@
- added namespace declaration in lovely/__init__.py
- allow to delay a job
-
Modified: lovely.remotetask/trunk/src/lovely/remotetask/README.txt
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/README.txt 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/src/lovely/remotetask/README.txt 2008-01-29 14:40:06 UTC (rev 83297)
@@ -107,6 +107,8 @@
The ``add()`` function schedules the task called "echo" to be executed with
the specified arguments. The method returns a job id with which we can inquire
about the job.
+By default the ``add()`` function adds and starts the job ASAP. Sometimes we need
+to have a jobid but not to start the job yet. See startlater.txt how.
>>> service.getStatus(jobid)
'queued'
@@ -720,3 +722,32 @@
False
>>> root_service.clean()
+
+
+Check Interfaces and stuff
+--------------------------
+
+ >>> from zope.interface.verify import verifyClass, verifyObject
+ >>> verifyClass(interfaces.ITaskService, remotetask.TaskService)
+ True
+ >>> verifyObject(interfaces.ITaskService, service)
+ True
+ >>> interfaces.ITaskService.providedBy(service)
+ True
+
+ >>> from lovely.remotetask.job import Job
+ >>> fakejob = Job(1, u'echo', {})
+ >>> verifyClass(interfaces.IJob, Job)
+ True
+ >>> verifyObject(interfaces.IJob, fakejob)
+ True
+ >>> interfaces.IJob.providedBy(fakejob)
+ True
+
+ >>> fakecronjob = CronJob(1, u'echo', {})
+ >>> verifyClass(interfaces.ICronJob, CronJob)
+ True
+ >>> verifyObject(interfaces.ICronJob, fakecronjob)
+ True
+ >>> interfaces.IJob.providedBy(fakecronjob)
+ True
\ No newline at end of file
Modified: lovely.remotetask/trunk/src/lovely/remotetask/browser/README.txt
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/browser/README.txt 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/src/lovely/remotetask/browser/README.txt 2008-01-29 14:40:06 UTC (rev 83297)
@@ -128,7 +128,7 @@
>>> 'Jobs were successfully cancelled.' in browser.contents
True
-It is also possible cancle all jobs::
+It is also possible cancel all jobs::
>>> browser.getControl('Cancel all', index=0).click()
>>> 'All jobs cancelled' in browser.contents
@@ -163,7 +163,7 @@
>>> from lovely.remotetask.interfaces import ITaskService
>>> service = getRootFolder()['tasks']
-We add e job for a task which raises a ZeroDivisionError every time it is
+We add a job for a task which raises a ZeroDivisionError every time it is
called.
>>> jobid = service.add(u'exception')
@@ -249,3 +249,11 @@
>>> service.getStatus(jobid)
'error'
+
+
+Clenaup
+-------
+
+Allow the threads to exit:
+
+ >>> sleep(0.2)
Modified: lovely.remotetask/trunk/src/lovely/remotetask/interfaces.py
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/interfaces.py 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/src/lovely/remotetask/interfaces.py 2008-01-29 14:40:06 UTC (rev 83297)
@@ -28,6 +28,8 @@
COMPLETED = 'completed'
DELAYED = 'delayed'
CRONJOB = 'cronjob'
+DELAYED = 'delayed'
+STARTLATER = 'start later'
class ITask(interface.Interface):
@@ -74,20 +76,22 @@
default = ITask,
)
- processor = schema.Field(
- title = u'Processor',
- description = u'A callable that processes queued jobs using '
- u'an infinite loop.',
- )
+ #processor = schema.Field(
+ # title = u'Processor',
+ # description = u'A callable that processes queued jobs using '
+ # u'an infinite loop.',
+ # )
def getAvailableTasks():
"""Return a mapping of task name to the task."""
- def add(task, input):
+ def add(task, input=None, startLater=False):
"""Add a new job for the specified task.
- The task argument is a string specifying the task. The input are
- arguments for the task.
+ * task argument is a string specifying the task.
+ * input are arguments for the task.
+ * startLater, if True job will be added (gets a jobid) but needs
+ to be started with startJob later
"""
def addCronJob(task, input,
@@ -99,6 +103,10 @@
):
"""Add a new cron job."""
+ def startJob(jobid):
+ """Start a job previously added job with add(..., startLater=True)
+ """
+
def reschedule(jobid):
"""Rescheudle a cron job.
@@ -168,7 +176,7 @@
title=u'Status',
description=u'The current status of the job.',
values=[QUEUED, PROCESSING, CANCELLED, ERROR,
- COMPLETED, DELAYED, CRONJOB],
+ COMPLETED, DELAYED, CRONJOB, STARTLATER],
required=True)
input = schema.Object(
@@ -256,7 +264,7 @@
The job must be rescheduled in the containing service.
"""
- def timeOfNextCall(self, now=None):
+ def timeOfNextCall(now=None):
"""Calculate the time for the next call of the job.
now is a convenience parameter for testing.
Modified: lovely.remotetask/trunk/src/lovely/remotetask/service.py
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/service.py 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/src/lovely/remotetask/service.py 2008-01-29 14:40:06 UTC (rev 83297)
@@ -64,7 +64,7 @@
"""See interfaces.ITaskService"""
return dict(component.getUtilitiesFor(self.taskInterface))
- def add(self, task, input=None):
+ def add(self, task, input=None, startLater=False):
"""See interfaces.ITaskService"""
if task not in self.getAvailableTasks():
raise ValueError('Task does not exist')
@@ -72,8 +72,11 @@
self._counter += 1
newjob = job.Job(jobid, task, input)
self.jobs[jobid] = newjob
- self._queue.put(newjob)
- newjob.status = interfaces.QUEUED
+ if startLater:
+ newjob.status = interfaces.STARTLATER
+ else:
+ self._queue.put(newjob)
+ newjob.status = interfaces.QUEUED
return jobid
def addCronJob(self, task, input=None,
@@ -96,6 +99,14 @@
self._scheduledQueue.put(newjob)
return jobid
+ def startJob(self, jobid):
+ job = self.jobs[jobid]
+ if job.status == interfaces.STARTLATER:
+ self._queue.put(job)
+ job.status = interfaces.QUEUED
+ return True
+ return False
+
def reschedule(self, jobid):
self._scheduledQueue.put(self.jobs[jobid])
@@ -123,6 +134,7 @@
job = self.jobs[jobid]
if ( job.status == interfaces.CRONJOB
or job.status == interfaces.DELAYED
+ or job.status == interfaces.STARTLATER
):
job.status = interfaces.CANCELLED
Copied: lovely.remotetask/trunk/src/lovely/remotetask/startlater.txt (from rev 83284, lovely.remotetask/branches/adamg-startlater/src/lovely/remotetask/startlater.txt)
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/startlater.txt (rev 0)
+++ lovely.remotetask/trunk/src/lovely/remotetask/startlater.txt 2008-01-29 14:40:06 UTC (rev 83297)
@@ -0,0 +1,129 @@
+=====================
+Remote Task Execution
+=====================
+
+Start later special
+~~~~~~~~~~~~~~~~~~~
+
+Usage
+_____
+
+ >>> STOP_SLEEP_TIME = 0.02
+
+Let's now start by creating a single service:
+
+ >>> from lovely import remotetask
+ >>> service = remotetask.TaskService()
+
+The object should be located, so it gets a name:
+
+ >>> from zope.app.folder import Folder
+ >>> site1 = Folder()
+ >>> root['site1'] = site1
+ >>> from zope.app.component.site import LocalSiteManager
+ >>> from zope.security.proxy import removeSecurityProxy
+ >>> sm = LocalSiteManager(removeSecurityProxy(site1))
+ >>> site1.setSiteManager(sm)
+
+ >>> sm['default']['testTaskService1'] = service
+ >>> service = sm['default']['testTaskService1'] # caution! proxy
+ >>> service.__name__
+ u'testTaskService1'
+ >>> service.__parent__ is sm['default']
+ True
+
+Let's register it under the name `TestTaskService1`:
+
+ >>> from zope import component
+ >>> from lovely.remotetask import interfaces
+ >>> sm = site1.getSiteManager()
+ >>> sm.registerUtility(service, interfaces.ITaskService,
+ ... name='TestTaskService1')
+
+Let's now define a task that simply echos an input string:
+
+ >>> def echo(input):
+ ... return input
+
+ >>> import lovely.remotetask.task
+ >>> echoTask = remotetask.task.SimpleTask(echo)
+
+Let's now register the task as a utility:
+
+ >>> import zope.component
+ >>> zope.component.provideUtility(echoTask, name='echo')
+
+Since the service cannot instantaneously complete a task, incoming jobs are
+managed by a queue.
+More than that, sometimes we need to have a jobid and the job in place with
+all inputs and stuff, but start it later.
+Watch for the ``startLater=True``.
+
+ >>> jobid = service.add(u'echo', {'foo': 'bar'}, startLater=True)
+ >>> jobid
+ 1
+
+The ``add()`` function schedules the task called "echo" to be executed with
+the specified arguments. The method returns a job id with which we can inquire
+about the job.
+
+ >>> service.getStatus(jobid)
+ 'start later'
+
+Since the job has not been added to the queue, the status is set to
+"start later". Further, there is no result available yet:
+
+ >>> service.getResult(jobid) is None
+ True
+
+As long as the job is not being processed, it can be cancelled:
+
+ >>> service.cancel(jobid)
+ >>> service.getStatus(jobid)
+ 'cancelled'
+
+Let's see how the starting later works.
+Add a job again:
+
+ >>> jobid = service.add(u'echo', {'foo': 'bar'}, startLater=True)
+ >>> jobid
+ 2
+
+It's still in the status ``start later``:
+
+ >>> service.getStatus(jobid)
+ 'start later'
+
+Do here some processing...
+Now start the job really:
+
+ >>> service.startJob(jobid)
+ True
+
+The status changed to ``queued``:
+
+ >>> service.getStatus(jobid)
+ 'queued'
+
+Starting the job again won't work:
+
+ >>> service.startJob(jobid)
+ False
+
+From this point on the job will behave as it were added with ``add`` without
+the ``startLater=True`` parameter.
+
+ >>> service.process()
+
+ >>> service.getStatus(jobid)
+ 'completed'
+
+ >>> service.getResult(jobid)
+ {'foo': 'bar'}
+
+ >>> service.getError(jobid)
+ 'None'
+
+ >>> service.stopProcessing()
+
+ >>> import time; time.sleep(STOP_SLEEP_TIME)
Modified: lovely.remotetask/trunk/src/lovely/remotetask/testing.py
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/testing.py 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/src/lovely/remotetask/testing.py 2008-01-29 14:40:06 UTC (rev 83297)
@@ -104,17 +104,30 @@
"""See interfaces.ITaskService"""
return dict(zope.component.getUtilitiesFor(self.taskInterface))
- def add(self, task, input=None):
+ def add(self, task, input=None, startLater=False, jobClass=None):
"""See interfaces.ITaskService"""
if task not in self.getAvailableTasks():
raise ValueError('Task does not exist')
+ if jobClass == None:
+ jobClass = job.Job
jobid = self._counter
self._counter += 1
- newjob = job.Job(jobid, task, input)
+ newjob = jobClass(jobid, task, input)
self.jobs[jobid] = newjob
- self._queue.put(newjob)
- newjob.status = interfaces.QUEUED
+ if startLater:
+ newjob.status = interfaces.STARTLATER
+ else:
+ self._queue.put(newjob)
+ newjob.status = interfaces.QUEUED
return jobid
+
+ def startJob(self, jobid):
+ job = self.jobs[jobid]
+ if job.status == interfaces.STARTLATER:
+ self._queue.put(job)
+ job.status = interfaces.QUEUED
+ return True
+ return False
def cancel(self, jobid):
"""See interfaces.ITaskService"""
Modified: lovely.remotetask/trunk/src/lovely/remotetask/tests.py
===================================================================
--- lovely.remotetask/trunk/src/lovely/remotetask/tests.py 2008-01-29 14:37:41 UTC (rev 83296)
+++ lovely.remotetask/trunk/src/lovely/remotetask/tests.py 2008-01-29 14:40:06 UTC (rev 83297)
@@ -54,6 +54,12 @@
|doctest.ELLIPSIS
|INTERPRET_FOOTNOTES
),
+ DocFileSuite('startlater.txt',
+ setUp=setUp,
+ tearDown=tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE
+ |doctest.ELLIPSIS
+ ),
DocFileSuite('processor.txt',
setUp=setUp,
tearDown=tearDown,
More information about the Checkins
mailing list