[Checkins] SVN: zc.resumelb/trunk/src/zc/resumelb/ Finished:

jim cvs-admin at zope.org
Thu Jul 5 12:55:50 UTC 2012


Log message for revision 127269:
  Finished:
  
  - Added support in the load balancer for applications that can't have
    multiple worker versions.  You can upgrade workers
    gradually. Workers with the new version will be ignored until
    they're in the majority, at which time the lb will stop using
    workers with the old version.
  
  By updating zk.py to:
  
  - Specofy worker versions in paste.ini,
  
  - Enabling the single_version option in the load balancer,
  
  - Passing version information to the load balancer.
  

Changed:
  U   zc.resumelb/trunk/src/zc/resumelb/README.txt
  U   zc.resumelb/trunk/src/zc/resumelb/tests.py
  U   zc.resumelb/trunk/src/zc/resumelb/zk.py
  U   zc.resumelb/trunk/src/zc/resumelb/zk.test

-=-
Modified: zc.resumelb/trunk/src/zc/resumelb/README.txt
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/README.txt	2012-07-04 18:19:31 UTC (rev 127268)
+++ zc.resumelb/trunk/src/zc/resumelb/README.txt	2012-07-05 12:55:46 UTC (rev 127269)
@@ -242,6 +242,15 @@
 Change History
 ==============
 
+0.7.0 (2012-07-05)
+------------------
+
+- Added support in the load balancer for applications that can't have
+  multiple worker versions.  You can upgrade workers
+  gradually. Workers with the new version will be ignored until
+  they're in the majority, at which time the lb will stop using
+  workers with the old version.
+
 0.6.2 (2012-06-15)
 ------------------
 

Modified: zc.resumelb/trunk/src/zc/resumelb/tests.py
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/tests.py	2012-07-04 18:19:31 UTC (rev 127268)
+++ zc.resumelb/trunk/src/zc/resumelb/tests.py	2012-07-05 12:55:46 UTC (rev 127269)
@@ -330,7 +330,7 @@
     zope.testing.setupstack.tearDown(test)
 
 def test_suite():
-    e1 = r'127.0.0.1:\d+\s+1\s+0.7\s+0'
+    e1 = r'127.0.0.1:\d+\s+1\s+0.7\s+[01]'
     e2 = r'127.0.0.1:\d+\s+0\s+0.0\s+-'
     return unittest.TestSuite((
         manuel.testing.TestSuite(
@@ -359,7 +359,8 @@
                         + '|' +
                         e2 + r'\s*\n\s*' + e1
                         + ')\s*'
-                        ), 'WORKERDETAILS')
+                        ), 'WORKERDETAILS'),
+                    (re.compile(r"127.0.0.1:\d+"), "127.0.0.1:DDDD"),
                     ])
                 ) + manuel.capture.Manuel(),
             'zk.test',

Modified: zc.resumelb/trunk/src/zc/resumelb/zk.py
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/zk.py	2012-07-04 18:19:31 UTC (rev 127268)
+++ zc.resumelb/trunk/src/zc/resumelb/zk.py	2012-07-05 12:55:46 UTC (rev 127269)
@@ -116,7 +116,6 @@
         '-a', '--address', default=':0',
         help="Address to listed on for web requests"
         )
-    parser.add_option('-l', '--access-logger', help='Access-log logger name.')
     parser.add_option(
         '-b', '--backlog', type='int',
         help="Server backlog setting.")
@@ -124,16 +123,11 @@
         '-d', '--backdoor', action='store_true',
         help="Run a backdoor server. Use with caution!")
     parser.add_option(
-        '-m', '--max-connections', type='int',
-        help="Maximum number of simultanious accepted connections.")
+        '-e', '--disconnect-message',
+        help="Path to error page to use when a request is lost due to "
+        "worker disconnection"
+        )
     parser.add_option(
-        '-s', '--status-server',
-        help=("Run a status server for getting pool information. "
-              "The argument is a unix-domain socket path to listen on."))
-    parser.add_option(
-        '-t', '--socket-timeout', type='float', default=99.,
-        help=('HTTP socket timeout.'))
-    parser.add_option(
         '-L', '--logger-configuration',
         help=
         "Read logger configuration from the given configuration file path.\n"
@@ -142,15 +136,24 @@
         "\n"
         "Alternatively, you can give a Python logger level name or number."
         )
+    parser.add_option('-l', '--access-logger', help='Access-log logger name.')
     parser.add_option(
+        '-m', '--max-connections', type='int',
+        help="Maximum number of simultanious accepted connections.")
+    parser.add_option(
         '-r', '--request-classifier', default='zc.resumelb.lb:host_classifier',
         help="Request classification function (module:expr)"
         )
     parser.add_option(
-        '-e', '--disconnect-message',
-        help="Path to error page to use when a request is lost due to "
-        "worker disconnection"
-        )
+        '-s', '--status-server',
+        help=("Run a status server for getting pool information. "
+              "The argument is a unix-domain socket path to listen on."))
+    parser.add_option(
+        '-t', '--socket-timeout', type='float', default=99.,
+        help=('HTTP socket timeout.'))
+    parser.add_option(
+        '-v', '--single-version', action='store_true',
+        help=('Only use a single worker version.'))
 
     try:
         options, args = parser.parse_args(args)
@@ -190,16 +193,34 @@
         disconnect_message = zc.resumelb.lb.default_disconnect_message
 
     from zc.resumelb.lb import LB
-    lb = LB(map(zc.parse_addr.parse_addr, addrs),
-            request_classifier, disconnect_message)
+    lb = LB(map(zc.parse_addr.parse_addr, ()),
+            request_classifier, disconnect_message,
+            single_version=options.single_version)
 
+
+    to_send = [[]]
     # Set up notification of address changes.
     awatcher = gevent.get_hub().loop.async()
     @awatcher.start
     def _():
-        lb.set_worker_addrs(map(zc.parse_addr.parse_addr, addrs))
-    addrs(lambda a: awatcher.send())
+        lb.set_worker_addrs(to_send[0])
 
+    if options.single_version:
+        @addrs
+        def get_addrs(a):
+            to_send[0] = dict(
+                (zc.parse_addr.parse_addr(addr),
+                 zk.get_properties(
+                     path+'/workers/providers/'+addr).get('version')
+                 )
+                for addr in addrs)
+            awatcher.send()
+    else:
+        @addrs
+        def get_addrs(a):
+            to_send[0] = map(zc.parse_addr.parse_addr, addrs)
+            awatcher.send()
+
     # Set up notification of address changes.
     settings = zk.properties(path)
     swatcher = gevent.get_hub().loop.async()

Modified: zc.resumelb/trunk/src/zc/resumelb/zk.test
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/zk.test	2012-07-04 18:19:31 UTC (rev 127268)
+++ zc.resumelb/trunk/src/zc/resumelb/zk.test	2012-07-05 12:55:46 UTC (rev 127269)
@@ -2,7 +2,7 @@
 ZooKeeper integration
 =====================
 
-    >>> import zc.resumelb.zk, zc.resumelb.tests, zc.zk
+    >>> import gevent, mock, zc.resumelb.zk, zc.resumelb.tests, zc.zk
     >>> zk = zc.zk.ZooKeeper('zookeeper.example.com:2181')
 
 To demonstrate the integration, we'll set up a tree:
@@ -61,7 +61,7 @@
 Let's create a worker, making sure that ZConfig.configureLoggers was called.
 
     >>> app = zc.resumelb.tests.app()
-    >>> import mock, marshal
+    >>> import marshal
     >>> with open('resume.mar', 'w') as f:
     ...     marshal.dump(dict(a=1.0, b=2.0), f)
     >>> with mock.patch('ZConfig.configureLoggers') as configureLoggers:
@@ -120,7 +120,7 @@
 A shutdown signal handler is registered.  We can call it to shut the
 worker down:
 
-    >>> import gevent, signal
+    >>> import signal
     >>> gevent.signal.call_args[0][0] == signal.SIGTERM
     True
 
@@ -197,32 +197,33 @@
       -h, --help            show this help message and exit
       -a ADDRESS, --address=ADDRESS
                             Address to listed on for web requests
-      -l ACCESS_LOGGER, --access-logger=ACCESS_LOGGER
-                            Access-log logger name.
       -b BACKLOG, --backlog=BACKLOG
                             Server backlog setting.
       -d, --backdoor        Run a backdoor server. Use with caution!
+      -e DISCONNECT_MESSAGE, --disconnect-message=DISCONNECT_MESSAGE
+                            Path to error page to use when a request is
+                            lost due to worker disconnection
+      -L LOGGER_CONFIGURATION, --logger-configuration=LOGGER_CONFIGURATION
+                            Read logger configuration from the given
+                            configuration file path.  The configuration
+                            file must be in ZConfig logger configuration
+                            syntax. Alternatively, you can give a Python
+                            logger level name or number.
+      -l ACCESS_LOGGER, --access-logger=ACCESS_LOGGER
+                            Access-log logger name.
       -m MAX_CONNECTIONS, --max-connections=MAX_CONNECTIONS
                             Maximum number of simultanious accepted
                             connections.
+      -r REQUEST_CLASSIFIER, --request-classifier=REQUEST_CLASSIFIER
+                            Request classification function
+                            (module:expr)
       -s STATUS_SERVER, --status-server=STATUS_SERVER
                             Run a status server for getting pool
                             information. The argument is a unix-domain
                             socket path to listen on.
       -t SOCKET_TIMEOUT, --socket-timeout=SOCKET_TIMEOUT
                             HTTP socket timeout.
-      -L LOGGER_CONFIGURATION, --logger-configuration=LOGGER_CONFIGURATION
-                            Read logger configuration from the given
-                            configuration file path.  The configuration
-                            file must be in ZConfig logger configuration
-                            syntax. Alternatively, you can give a Python
-                            logger level name or number.
-      -r REQUEST_CLASSIFIER, --request-classifier=REQUEST_CLASSIFIER
-                            Request classification function
-                            (module:expr)
-      -e DISCONNECT_MESSAGE, --disconnect-message=DISCONNECT_MESSAGE
-                            Path to error page to use when a request is
-                            lost due to worker disconnection
+      -v, --single-version  Only use a single worker version.
 
 
 Let's start with a simple call:
@@ -487,8 +488,7 @@
     >>> print sock.recv(9999) # doctest: +ELLIPSIS
     HTTP/1.0 200 OK...
 
-    >>> server.stop()
-    >>> lb.stop()
+    >>> lb_greenlet.kill()
 
 Try a numeric log level:
 
@@ -501,5 +501,38 @@
     ...     if configureLoggers.called: print 'configureLoggers'
     ...     basicConfig.assert_called_with(level=42)
 
-    >>> server.stop()
-    >>> lb.stop()
+
+    >>> lb_greenlet.kill()
+    >>> worker_greenlet.kill()
+
+Single-version load balancer
+=============================
+
+If only one version of your application should run at a time, you can
+use the single-version (``-v``, ``--single-version``) option.  Your
+workers must register with a version, or they'll be ignored.
+
+    >>> with mock.patch('ZConfig.configureLoggers') as configureLoggers:
+    ...   with mock.patch('logging.basicConfig') as basicConfig:
+    ...     worker = zc.resumelb.zk.worker(
+    ...         app, None,
+    ...         zookeeper='zookeeper.example.com:2181', path='/test/lb/workers',
+    ...         address='127.0.0.1:0', run=False, version='42')
+    >>> gevent.sleep(.01)
+    >>> lb, server = zc.resumelb.zk.lbmain(
+    ...     'zookeeper.example.com:2181 /test/lb -v')
+    >>> gevent.sleep(1)
+    >>> with mock.patch('ZConfig.configureLoggers') as configureLoggers:
+    ...   with mock.patch('logging.basicConfig') as basicConfig:
+    ...     worker = zc.resumelb.zk.worker(
+    ...         app, None,
+    ...         zookeeper='zookeeper.example.com:2181', path='/test/lb/workers',
+    ...         address='127.0.0.1:0', run=False, version='42')
+    >>> gevent.sleep(.01)
+    >>> lb.pool
+    Version: 42
+    Request classes:
+    Backlogs:
+      overall backlog: 0 Decayed: 0 Avg: 0
+      0: [127.0.0.1:39208, 127.0.0.1:60073]
+



More information about the checkins mailing list