As described above, using a shared single database will probably be the quickest way to get started. Large-scale production usage will probably prefer to use the Two Database Set Up described later.
So, without further ado, here is the text of our zope.conf-alike, and of our site.zcml-alike [1].
>>> zope_conf = """
... site-definition %(site_zcml_file)s
...
... <zodb main>
... <filestorage>
... create true
... path %(main_storage_path)s
... </filestorage>
... </zodb>
...
... <product-config zc.z3monitor>
... port %(monitor_port)s
... </product-config>
...
... <logger>
... level debug
... name zc.async
... propagate no
...
... <logfile>
... path %(async_event_log)s
... </logfile>
... </logger>
...
... <logger>
... level debug
... name zc.async.trace
... propagate no
...
... <logfile>
... path %(async_trace_log)s
... </logfile>
... </logger>
...
... <eventlog>
... <logfile>
... formatter zope.exceptions.log.Formatter
... path STDOUT
... </logfile>
... <logfile>
... formatter zope.exceptions.log.Formatter
... path %(event_log)s
... </logfile>
... </eventlog>
... """ % {'site_zcml_file': site_zcml_file,
... 'main_storage_path': os.path.join(dir, 'main.fs'),
... 'async_storage_path': os.path.join(dir, 'async.fs'),
... 'monitor_port': monitor_port,
... 'event_log': os.path.join(dir, 'z3.log'),
... 'async_event_log': os.path.join(dir, 'async.log'),
... 'async_trace_log': os.path.join(dir, 'async_trace.log'),}
...
In a non-trivial production system, you will also probably want to replace the file storage with a <zeoclient> stanza.
Also note that an open monitor port should be behind a firewall, of course.
We’ll assume that zdaemon.conf has been set up to put ZC_ASYNC_UUID in the proper place too. It would have looked something like this in the zdaemon.conf:
<environment> ZC_ASYNC_UUID /path/to/uuid.txt </environment>
(Other tools, such as supervisor, also can work, of course; their spellings are different and are “left as an exercise to the reader” at the moment.)
We’ll do that by hand:
>>> os.environ['ZC_ASYNC_UUID'] = os.path.join(dir, 'uuid.txt')
Now let’s define our site-zcml-alike.
>>> site_zcml = """
... <configure xmlns='http://namespaces.zope.org/zope'
... xmlns:meta="http://namespaces.zope.org/meta"
... >
... <include package="zope.component" file="meta.zcml" />
... <include package="zope.component" />
... <include package="zc.z3monitor" />
... <include package="zc.async" file="basic_dispatcher_policy.zcml" />
...
... <!-- this is usually handled in Zope applications by the
... zope.app.keyreference.persistent.connectionOfPersistent adapter -->
... <adapter factory="zc.twist.connection" />
... </configure>
... """
Now we’re done.
If we process these files, and wait for a poll, we’ve got a working set up [2].
>>> import zc.async.dispatcher
>>> dispatcher = zc.async.dispatcher.get()
>>> import pprint
>>> pprint.pprint(get_poll(dispatcher, 0))
{'': {'main': {'active jobs': [],
'error': None,
'len': 0,
'new jobs': [],
'size': 3}}}
>>> bool(dispatcher.activated)
True
We can ask for a job to be performed, and get the result.
>>> conn = db.open()
>>> root = conn.root()
>>> import zc.async.interfaces
>>> queue = zc.async.interfaces.IQueue(root)
>>> import operator
>>> import zc.async.job
>>> job = queue.put(zc.async.job.Job(operator.mul, 21, 2))
>>> import transaction
>>> transaction.commit()
>>> wait_for_result(job)
42
We can connect to the monitor server with telnet.
>>> import telnetlib
>>> tn = telnetlib.Telnet('127.0.0.1', monitor_port)
>>> tn.write('async status\n') # immediately disconnects
>>> print tn.read_all() # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
{
"poll interval": {
"seconds": ...
},
"status": "RUNNING",
"time since last poll": {
"seconds": ...
},
"uptime": {
"seconds": ...
},
"uuid": "..."
}
<BLANKLINE>
Now we’ll “shut down” with a CTRL-C, or SIGINT, and clean up.
>>> import signal >>> if getattr(os, 'getpid', None) is not None: # UNIXEN, not Windows ... pid = os.getpid() ... try: ... os.kill(pid, signal.SIGINT) ... except KeyboardInterrupt: ... if dispatcher.activated: ... assert False, 'dispatcher did not deactivate' ... else: ... print "failed to send SIGINT, or something" ... else: ... dispatcher.reactor.callFromThread(dispatcher.reactor.stop) ... for i in range(30): ... if not dispatcher.activated: ... break ... time.sleep(0.1) ... else: ... assert False, 'dispatcher did not deactivate' ... >>> import transaction >>> t = transaction.begin() # sync >>> import zope.component >>> import zc.async.interfaces >>> uuid = zope.component.getUtility(zc.async.interfaces.IUUID) >>> da = queue.dispatchers[uuid] >>> bool(da.activated) False>>> db.close() >>> import shutil >>> shutil.rmtree(dir)
These instructions are very similar to the Two Database Set Up.
Footnotes
[1] | >>> import errno, os, random, socket, tempfile
>>> dir = tempfile.mkdtemp()
>>> site_zcml_file = os.path.join(dir, 'site.zcml')
>>> s = socket.socket()
>>> for i in range(20):
... monitor_port = random.randint(20000, 49151)
... try:
... s.bind(('127.0.0.1', monitor_port))
... except socket.error, e:
... if e.args[0] == errno.EADDRINUSE:
... pass
... else:
... raise
... else:
... s.close()
... break
... else:
... assert False, 'could not find available port'
... monitor_port = None
...
|
[2] | >>> zope_conf_file = os.path.join(dir, 'zope.conf')
>>> f = open(zope_conf_file, 'w')
>>> f.write(zope_conf)
>>> f.close()
>>> f = open(site_zcml_file, 'w')
>>> f.write(site_zcml)
>>> f.close()
>>> import zdaemon.zdoptions
>>> import zope.app.appsetup
>>> options = zdaemon.zdoptions.ZDOptions()
>>> options.schemadir = os.path.join(
... os.path.dirname(os.path.abspath(zope.app.appsetup.__file__)),
... 'schema')
>>> options.realize(['-C', zope_conf_file])
>>> config = options.configroot
>>> import zope.app.appsetup.product
>>> zope.app.appsetup.product.setProductConfigurations(
... config.product_config)
>>> ignore = zope.app.appsetup.config(config.site_definition)
>>> import zope.app.appsetup.appsetup
>>> db = zope.app.appsetup.appsetup.multi_database(config.databases)[0][0]
>>> import zope.event
>>> import zc.async.interfaces
>>> zope.event.notify(zc.async.interfaces.DatabaseOpened(db))
>>> from zc.async.testing import get_poll, wait_for_result
|