[Checkins]
SVN: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/
Zope 2.10 compatible version. MultiProcessor does not work as
expected yet, but single processor or job management page works.
Radim Novotny
novotny.radim at gmail.com
Wed May 14 04:34:23 EDT 2008
Log message for revision 86722:
Zope 2.10 compatible version. MultiProcessor does not work as expected yet, but single processor or job management page works.
Changed:
U lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py
U lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml
U lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py
A lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml
U lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml
U lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py
U lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py
-=-
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py 2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py 2008-05-14 08:34:23 UTC (rev 86722)
@@ -1,2 +1,31 @@
# Make a package.
from lovely.remotetask.service import TaskService
+
+try:
+ from Products.Five.site.interfaces import IFiveUtilityRegistry
+ ZOPE2=True
+except ImportError:
+ ZOPE2=False
+
+# This is implemented as IDatabaseOpenedEvent in Zope 3
+if ZOPE2:
+ from lovely.remotetask.service import TaskService, getAutostartServiceNames
+ from lovely.remotetask.interfaces import ITaskService
+ from zope.component import getUtilitiesFor
+ from zope.app.component.hooks import getSite
+ from Products.CMFCore.interfaces._content import ISiteRoot
+
+ def initialize(context):
+ # dirty trick, but it works
+ app = context._ProductContext__app
+ services = getAutostartServiceNames()
+
+ for service in services:
+ site_name, service_name = service.split('@')
+ if site_name:
+ site = getattr(app, site_name, None)
+ if site:
+ registry = site.getSiteManager()
+ service = registry.queryUtility(ITaskService, name=service_name)
+ if ITaskService.providedBy(service) and not service.isProcessing():
+ service.startProcessing()
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml 2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml 2008-05-14 08:34:23 UTC (rev 86722)
@@ -1,5 +1,6 @@
<configure
xmlns="http://namespaces.zope.org/browser"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
xmlns:zope="http://namespaces.zope.org/zope">
<resourceDirectory
@@ -8,6 +9,7 @@
/>
<addMenuItem
+ zcml:condition="not-installed Products.Five"
class="..service.TaskService"
title="Remote Task Service"
description="A Remote Task Service"
@@ -15,6 +17,7 @@
/>
<page
+ zcml:condition="not-installed Products.Five"
name="jobs.html"
for="..interfaces.ITaskService"
class=".service.JobsOverview"
@@ -23,6 +26,7 @@
/>
<page
+ zcml:condition="not-installed Products.Five"
name="detail"
for="..interfaces.IJob"
permission="zope.ManageContent"
@@ -30,6 +34,7 @@
/>
<page
+ zcml:condition="not-installed Products.Five"
name="detail"
for="..interfaces.ICronJob"
permission="zope.Public"
@@ -37,6 +42,7 @@
/>
<page
+ zcml:condition="not-installed Products.Five"
name="editjob"
for="..interfaces.ICronJob"
permission="zope.ManageContent"
@@ -45,6 +51,7 @@
/>
<page
+ zcml:condition="not-installed Products.Five"
name="addcronjob.html"
for="..interfaces.ITaskService"
class=".job.AddCronJob"
@@ -61,4 +68,6 @@
permission="zope.Public"
/>
+ <include file="zope210compat.zcml" zcml:condition="installed Products.Five" />
+
</configure>
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py 2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py 2008-05-14 08:34:23 UTC (rev 86722)
@@ -35,6 +35,12 @@
# But still support the old location if we can't get it from the new:
from zope.app.session.interfaces import ISession
+try:
+ from Products import Five
+ ZOPE2 = True
+except ImportError:
+ ZOPE2 = False
+
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.app.container.contained import contained
@@ -202,9 +208,13 @@
def renderCell(self, item, formatter):
date = self.getter(item, formatter)
- dformat = formatter.request.locale.dates.getFormatter(
- 'dateTime', 'medium')
- return date and dformat.format(date) or '[not set]'
+ if not ZOPE2:
+ dformat = formatter.request.locale.dates.getFormatter(
+ 'dateTime', 'medium')
+ return date and dformat.format(date) or '[not set]'
+ else:
+ # request has no 'locale'
+ return date or '[not set]'
def getSortKey(self, item, formatter):
return self.getter(item, formatter)
@@ -396,6 +406,14 @@
return self.template()
from zope.publisher.interfaces import IPublishTraverse
+try:
+ from Products import Five
+ from Acquisition import aq_base, aq_inner
+ ZOPE2 = True
+ del Five
+except ImportError:
+ ZOPE2 = False
+
class ServiceJobTraverser(object):
zope.interface.implements(IPublishTraverse)
@@ -415,5 +433,10 @@
name=name)
if view is not None:
return view
- raise NotFound(self.context, name, request)
+ else:
+ if ZOPE2:
+ obj = getattr(aq_base(aq_inner(self.context)), name, None)
+ if obj is not None:
+ return obj
+ raise NotFound(self.context, name, request)
Added: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml (rev 0)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml 2008-05-14 08:34:23 UTC (rev 86722)
@@ -0,0 +1,41 @@
+<configure
+ xmlns="http://namespaces.zope.org/browser"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ xmlns:zope="http://namespaces.zope.org/zope">
+
+ <page
+ name="jobs.html"
+ for="..interfaces.ITaskService"
+ class=".service.JobsOverview"
+ permission="zope.Public"
+ />
+
+ <page
+ name="detail"
+ for="..interfaces.IJob"
+ permission="zope.Public"
+ class=".job.JobDetail"
+ />
+
+ <page
+ name="detail"
+ for="..interfaces.ICronJob"
+ permission="zope.Public"
+ class=".job.CronJobDetail"
+ />
+
+ <page
+ name="editjob"
+ for="..interfaces.ICronJob"
+ permission="zope.Public"
+ class=".job.CronJobEdit"
+ />
+
+ <page
+ name="addcronjob.html"
+ for="..interfaces.ITaskService"
+ class=".job.AddCronJob"
+ permission="zope.Public"
+ />
+
+</configure>
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml 2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml 2008-05-14 08:34:23 UTC (rev 86722)
@@ -1,5 +1,7 @@
<configure
xmlns="http://namespaces.zope.org/zope"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ xmlns:five="http://namespaces.zope.org/five"
i18n_domain="lovely.remotetask">
<class class=".service.TaskService">
@@ -38,8 +40,9 @@
factory=".task.EchoTask"
name="echo" />
- <include file="xmlrpc.zcml" />
-
+ <include zcml:condition="not-installed Products.Five" file="xmlrpc.zcml" />
+ <five:registerPackage zcml:condition="installed Products.Five" package="." initialize=".initialize" />
+
<include package=".browser" />
<include package=".generations" />
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py 2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py 2008-05-14 08:34:23 UTC (rev 86722)
@@ -28,6 +28,15 @@
from zope.security.proxy import removeSecurityProxy
from zope.traversing.api import traverse
+try:
+ from ZPublisher.HTTPRequest import HTTPRequest
+ from ZPublisher.HTTPResponse import HTTPResponse
+ import ZPublisher
+ from types import StringType
+ ZOPE2=True
+except ImportError:
+ ZOPE2=False
+
from lovely.remotetask import interfaces
THREAD_STARTUP_WAIT = 0.05
@@ -92,7 +101,7 @@
log.error('Processor: ``%s()`` caused an error!' %method)
log.exception(error)
return errorValue is ERROR_MARKER and error or errorValue
-
+
def processNext(self, jobid=None):
return self.call('processNext', args=(None, jobid))
@@ -104,7 +113,38 @@
if not result:
time.sleep(self.waitTime)
+class SimpleZope2Processor(SimpleProcessor):
+ """ SimpleProcessor for Zope2 """
+
+ zope.interface.implements(interfaces.IProcessor)
+ def call(self, method, args=(), errorValue=ERROR_MARKER):
+ path = [method] + self.servicePath[:]
+ path.reverse()
+ response = HTTPResponse()
+ env = { 'SERVER_NAME': 'dummy',
+ 'SERVER_PORT': '8080',
+ 'PATH_INFO': '/' + '/'.join(path) }
+ request = HTTPRequest(None, env, response)
+ conn = self.db.open()
+ root = conn.root()
+ request['PARENTS'] = [root[ZopePublication.root_name]]
+ try:
+ try:
+ ZPublisher.Publish.publish(request,'Zope2', [None])
+ except Exception, error:
+ # This thread should never crash, thus a blank except
+ log.error('Processor: ``%s()`` caused an error!' %method)
+ log.exception(error)
+ return errorValue is ERROR_MARKER and error or errorValue
+ finally:
+ request.close()
+ conn.close()
+ if not request.response.body:
+ time.sleep(1)
+ else:
+ return request.response.body
+
class MultiProcessor(SimpleProcessor):
"""Multi-threaded Job Processor
@@ -150,3 +190,34 @@
thread.start()
# Give the thread some time to start up:
time.sleep(THREAD_STARTUP_WAIT)
+
+class MultiZope2Processor(MultiProcessor, SimpleZope2Processor):
+ """Multi-threaded Job Processor
+
+ This processor can work on multiple jobs at the same time.
+
+ WARNING: This still does not work correctly in Zope2
+ """
+ zope.interface.implements(interfaces.IProcessor)
+
+ def __init__(self, *args, **kwargs):
+ self.maxThreads = kwargs.pop('maxThreads', 5)
+ super(MultiZope2Processor, self).__init__(*args, **kwargs)
+ self.threads = []
+
+ def hasJobsWaiting(self):
+ value = self.call('hasJobsWaiting', errorValue=False)
+ if isinstance(value, StringType):
+ if value == 'True':
+ return True
+ else:
+ return False
+ return value
+
+ def claimNextJob(self):
+ value = self.call('claimNextJob', errorValue=None)
+ try:
+ value = int(value)
+ except ValueError:
+ pass
+ return value
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py 2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py 2008-05-14 08:34:23 UTC (rev 86722)
@@ -27,7 +27,6 @@
from BTrees.IOBTree import IOBTree
from zope import component
from zope.app import zapi
-from zope.app.appsetup.product import getProductConfiguration
from zope.app.container import contained
from zope.app.component.interfaces import ISite
from zope.app.publication.zopepublication import ZopePublication
@@ -36,6 +35,15 @@
log = logging.getLogger('lovely.remotetask')
+try:
+ from Products import Five
+ from App.config import getConfiguration
+ ZOPE2 = True
+ del Five
+except ImportError:
+ from zope.app.appsetup.product import getProductConfiguration
+ ZOPE2 = False
+
storage = threading.local()
class TaskService(contained.Contained, persistent.Persistent):
@@ -46,7 +54,11 @@
zope.interface.implements(interfaces.ITaskService)
taskInterface = interfaces.ITask
- processorFactory = processor.SimpleProcessor
+ if not ZOPE2:
+ processorFactory = processor.SimpleProcessor
+ else:
+ processorFactory = processor.SimpleZope2Processor
+
processorArguments = {'waitTime': 1.0}
_scheduledJobs = None
@@ -159,10 +171,13 @@
if self._scheduledQueue == None:
self._scheduledQueue = zc.queue.PersistentQueue()
# Create the path to the service within the DB.
- servicePath = [parent.__name__ for parent in zapi.getParents(self)
- if parent.__name__]
+ if not ZOPE2:
+ servicePath = [parent.__name__ for parent in zapi.getParents(self)
+ if parent.__name__]
+ servicePath.append(self.__name__)
+ else:
+ servicePath = [path for path in self.getPhysicalPath() if path]
servicePath.reverse()
- servicePath.append(self.__name__)
# Start the thread running the processor inside.
processor = self.processorFactory(
self._p_jar.db(), servicePath, **self.processorArguments)
@@ -196,11 +211,16 @@
"""Return name of the processing thread."""
# This name isn't unique based on the path to self, but this doesn't
# change the name that's been used in past versions.
- path = [parent.__name__ for parent in zapi.getParents(self)
- if parent.__name__]
- path.append('remotetasks')
- path.reverse()
- path.append(self.__name__)
+ if not ZOPE2:
+ path = [parent.__name__ for parent in zapi.getParents(self)
+ if parent.__name__]
+ path.append('remotetasks')
+ path.reverse()
+ path.append(self.__name__)
+ else:
+ path = [path for path in self.getPhysicalPath() if path]
+ path.append('remotetasks')
+ path.reverse()
return '.'.join(path)
def hasJobsWaiting(self, now=None):
@@ -334,13 +354,26 @@
"""get a list of services to start"""
serviceNames = []
- config = getProductConfiguration('lovely.remotetask')
- if config is not None:
- serviceNames = [name.strip()
- for name in config.get('autostart', '').split(',')]
+ # this does not work in Zope 2, because there is no "getProductConfiguration"
+ # Services has to be started in custom code
+ if not ZOPE2:
+ config = getProductConfiguration('lovely.remotetask')
+ if config is not None:
+ serviceNames = [name.strip()
+ for name in config.get('autostart', '').split(',')]
+ else:
+ config = getConfiguration().product_config
+ if config is not None:
+ task_config = config.get('lovely.remotetask', None)
+ if task_config:
+ autostart = task_config.get('autostart', '')
+ serviceNames = [name.strip()
+ for name in autostart.split(',')]
+
return serviceNames
+
def bootStrapSubscriber(event):
"""Start the queue processing services based on the
settings in zope.conf"""
@@ -404,3 +437,4 @@
if (siteName == "*" or serviceName == "*") and serviceCount == 0:
msg = 'no services started by directive %s'
log.warn(msg % name)
+
More information about the Checkins
mailing list