Work in progress: set up basic agent functionality (with unit tests...)

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1783 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-06-09 15:42:11 +00:00
parent a7bd96600b
commit d66bd7591c
6 changed files with 106 additions and 12 deletions

View file

@ -20,6 +20,9 @@ This means that all calls to services (like crawler, transporter, ...)
return a deferred that must be supplied with a callback method (and in return a deferred that must be supplied with a callback method (and in
most cases also an errback method). most cases also an errback method).
>>> from loops.agent.core import Agent
>>> agent = Agent()
Browser-based User Interface Browser-based User Interface
============================ ============================
@ -46,6 +49,24 @@ Configuration (per job)
- schedule, repeating pattern, conditions - schedule, repeating pattern, conditions
- following job(s), e.g. to start a transfer immediately after a crawl - following job(s), e.g. to start a transfer immediately after a crawl
>>> scheduler = agent.scheduler
>>> from time import time
>>> from loops.agent.schedule import Job
>>> class TestJob(Job):
... def execute(self, **kw):
... d = super(TestJob, self).execute(**kw)
... print 'executing'
... return d
>>> scheduler.schedule(TestJob(), int(time())+1)
>>> from twisted.internet import reactor
>>> ignore = reactor.callLater(2, reactor.stop)
>>> reactor.run()
executing
Crawling Crawling
======== ========

View file

@ -25,6 +25,7 @@ $Id$
from zope.interface import implements from zope.interface import implements
from loops.agent.interfaces import IAgent from loops.agent.interfaces import IAgent
from loops.agent.config import Configurator from loops.agent.config import Configurator
from loops.agent.schedule import Scheduler
class Agent(object): class Agent(object):
@ -34,8 +35,5 @@ class Agent(object):
def __init__(self): def __init__(self):
configurator = self.configurator = Configurator() configurator = self.configurator = Configurator()
configurator.loadConfiguration() configurator.loadConfiguration()
self.scheduler = Scheduler()
def startAgent():
return Agent()

View file

@ -30,6 +30,8 @@ class IAgent(Interface):
and transfers these to its server. and transfers these to its server.
""" """
scheduler = Attribute('IScheduler instance')
class IScheduler(Interface): class IScheduler(Interface):
""" Manages jobs and cares that they are started at the appropriate """ Manages jobs and cares that they are started at the appropriate

View file

@ -1,7 +1,7 @@
from twisted.application import internet, service from twisted.application import internet, service
from nevow import appserver from nevow import appserver
from loops.agent.core import startAgent from loops.agent.core import Agent
from loops.agent.ui.web import AgentHome from loops.agent.ui.web import AgentHome
from loops.agent.config import conf from loops.agent.config import conf
@ -9,7 +9,7 @@ port = conf.ui.web.port or 10095
application = service.Application('LoopsAgent') application = service.Application('LoopsAgent')
site = appserver.NevowSite(resource=AgentHome(startAgent())) site = appserver.NevowSite(resource=AgentHome(Agent()))
webServer = internet.TCPServer(port, site) webServer = internet.TCPServer(port, site)
webServer.setServiceParent(application) webServer.setServiceParent(application)

View file

@ -22,5 +22,63 @@ Job scheduling.
$Id$ $Id$
""" """
from time import time
from twisted.internet import reactor
from twisted.internet.defer import Deferred
from zope.interface import implements
from loops.agent.interfaces import IScheduler, IScheduledJob from loops.agent.interfaces import IScheduler, IScheduledJob
class Scheduler(object):
implements(IScheduler)
def __init__(self):
self.queue = {}
self.Logger = None
def schedule(self, job, startTime):
job.startTime = startTime
job.scheduler = self
self.queue[startTime] = job
reactor.callLater(startTime-int(time()), job.run, **job.params)
def getJobsToExecute(startTime=None):
return [j for j in self.queue.values() if (startTime or 0) <= j.startTime]
class Job(object):
implements(IScheduledJob)
def __init__(self):
self.startTime = 0
self.scheduler = None
self.params = {}
self.successors = []
def execute(self, **kw):
d = Deferred()
return d
def reschedule(self, startTime):
self.scheduler.schedule(self.copy(), startTime)
def run(self, **kw):
d = self.execute(**kw)
d.addCallback(self.finishRun)
# TODO: logging
def finishRun(self, result):
for job in self.successors:
job.run(job, **job.params)
# TODO: remove from queue
# TODO: logging
# TODO: reschedule if told by configuration
def copy(self):
newJob = Job()
newJob.params = self.params
newJob.successors = [s.copy() for s in self.successors]

View file

@ -1,22 +1,37 @@
# $Id$ # $Id$
import unittest, doctest import unittest, doctest
from zope.testing.doctestunit import DocFileSuite import time
from zope.interface.verify import verifyClass from twisted.internet import reactor
from loops.expert import query
from loops.agent.core import Agent
from loops.agent.schedule import Job
class TestJob(Job):
def execute(self, **kw):
d = super(TestJob, self).execute(**kw)
print 'executing'
return d
class Test(unittest.TestCase): class Test(unittest.TestCase):
"Basic tests for the loops.agent package." "Basic tests for the loops.agent package."
def testSomething(self): def setUp(self):
pass self.agent = Agent()
def testScheduling(self):
d = self.agent.scheduler.schedule(TestJob(), int(time.time())+1)
time.sleep(1)
def test_suite(): def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
return unittest.TestSuite(( return unittest.TestSuite((
unittest.makeSuite(Test), unittest.makeSuite(Test),
DocFileSuite('README.txt', optionflags=flags), doctest.DocFileSuite('README.txt', optionflags=flags),
)) ))
if __name__ == '__main__': if __name__ == '__main__':