----------------------------- Shared Single Database Set Up ----------------------------- 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 :ref:`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 [#get_vals]_. >>> zope_conf = """ ... site-definition %(site_zcml_file)s ... ... ... ... create true ... path %(main_storage_path)s ... ... ... ... ... port %(monitor_port)s ... ... ... ... level debug ... name zc.async ... propagate no ... ... ... path %(async_event_log)s ... ... ... ... ... level debug ... name zc.async.trace ... propagate no ... ... ... path %(async_trace_log)s ... ... ... ... ... ... formatter zope.exceptions.log.Formatter ... path STDOUT ... ... ... formatter zope.exceptions.log.Formatter ... path %(event_log)s ... ... ... """ % {'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 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:: ZC_ASYNC_UUID /path/to/uuid.txt (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 = """ ... ... ... ... ... ... ... ... ... ... """ Now we're done. If we process these files, and wait for a poll, we've got a working set up [#process]_. >>> 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": "..." } 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 :ref:`two-database-set-up`. .. rubric:: Footnotes .. [#get_vals] >>> 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 ... .. [#process] >>> 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