Changeset - 1e2491a5a9fa
[Not reviewed]
0 3 0
Lance Edgar (lance) - 11 years ago 2013-11-16 01:07:57
lance@edbob.org
More db sync fixes (tested on Windows).
3 files changed with 11 insertions and 9 deletions:
0 comments (0 inline, 0 general)
rattail/db/sync/__init__.py
Show inline comments
 
@@ -94,25 +94,25 @@ class Synchronizer(object):
 
    you have special processing needs.
 
    """
 

	
 
    def __init__(self, local_engine, remote_engines):
 
        self.local_engine = local_engine
 
        self.remote_engines = remote_engines
 

	
 
    def loop(self):
 
        log.info("Synchronizer.loop: using remote engines: {0}".format(
 
                ', '.join(self.remote_engines.iterkeys())))
 
        while True:
 
            try:
 
                self.synchronize_changes()
 
                self.synchronize()
 
            except OperationalError, error:
 
                if error.connection_invalidated:
 
                    # Presumably a database server restart; give it a moment
 
                    # and try again.
 
                    self.sleep(5)
 
                else:
 
                    raise
 
            self.sleep(3)
 

	
 
    def sleep(self, seconds): # pragma no cover
 
        if sys.platform == 'win32':
 
            win32api.Sleep(seconds * 1000)
 
@@ -294,18 +294,20 @@ def synchronize_changes(local_engine, remote_engines):
 

	
 
    .. highlight:: ini
 

	
 
    If you need to override the default synchronizer class, put something like
 
    the following in your config file::
 

	
 
       [rattail.db]
 
       sync.synchronizer_class = myapp.sync:MySynchronizer
 
    """
 

	
 
    factory = edbob.config.get('rattail.db', 'sync.synchronizer_class')
 
    if factory:
 
        log.debug("synchronize_changes: using custom synchronizer factory: {0}".format(repr(factory)))
 
        factory = edbob.load_spec(factory)
 
    else:
 
        log.debug("synchronize_changes: using default synchronizer factory")
 
        factory = Synchronizer
 

	
 
    synchronizer = factory(local_engine, remote_engines)
 
    synchronizer.loop()
rattail/db/sync/win32.py
Show inline comments
 
@@ -22,26 +22,27 @@
 
#
 
################################################################################
 

	
 
"""
 
``rattail.db.sync.win32`` -- Database Synchronization for Windows
 
"""
 

	
 
import sys
 
import logging
 
import threading
 

	
 
import edbob
 
from edbob.win32 import Service
 
from edbob import db
 

	
 
from rattail.win32.service import Service
 
from rattail.db.sync import get_sync_engines, synchronize_changes
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class DatabaseSynchronizerService(Service):
 
    """
 
    Implements database synchronization as a Windows service.
 
    """
 

	
 
    _svc_name_ = 'RattailDatabaseSynchronizer'
 
@@ -53,28 +54,27 @@ class DatabaseSynchronizerService(Service):
 
    appname = 'rattail'
 

	
 
    def Initialize(self):
 
        """
 
        Service initialization.
 
        """
 

	
 
        if not Service.Initialize(self):
 
            return False
 

	
 
        edbob.init_modules(['rattail.db'])
 

	
 
        engines = get_sync_engines()
 
        if not engines:
 
        remote_engines = get_sync_engines()
 
        if not remote_engines:
 
            return False
 

	
 
        thread = threading.Thread(target=synchronize_changes,
 
                                  args=(engines,))
 
                                  args=(db.engine, remote_engines))
 
        thread.daemon = True
 
        thread.start()
 

	
 
        return True
 

	
 

	
 
if __name__ == '__main__':
 
    if sys.platform == 'win32':
 
        import win32serviceutil
 
        win32serviceutil.HandleCommandLine(DatabaseSynchronizerService)
tests/db/sync/test_init.py
Show inline comments
 
@@ -27,30 +27,30 @@ class SynchronizerTests(TestCase):
 
        synchronizer = sync.Synchronizer(self.local_engine, self.remote_engines)
 
        self.assertIs(synchronizer.local_engine, self.local_engine)
 
        self.assertIs(synchronizer.remote_engines, self.remote_engines)
 

	
 
    def test_loop(self):
 

	
 
        class FakeOperationalError(OperationalError):
 
            def __init__(self, connection_invalidated):
 
                self.connection_invalidated = connection_invalidated
 

	
 
        synchronizer = sync.Synchronizer(self.local_engine, self.remote_engines)
 
        with patch.object(synchronizer, 'sleep') as sleep:
 
            with patch.object(synchronizer, 'synchronize_changes') as synchronize_changes:
 
            with patch.object(synchronizer, 'synchronize') as synchronize:
 

	
 
                synchronize_changes.side_effect = [1, 2, 3, FakeOperationalError(True),
 
                synchronize.side_effect = [1, 2, 3, FakeOperationalError(True),
 
                                                   5, 6, 7, FakeOperationalError(False)]
 
                self.assertRaises(FakeOperationalError, synchronizer.loop)
 
                self.assertEqual(synchronize_changes.call_count, 8)
 
                self.assertEqual(synchronize.call_count, 8)
 
                self.assertEqual(sleep.call_args_list, [
 
                        call(3), call(3), call(3), call(5), call(3),
 
                        call(3), call(3), call(3)])
 

	
 
    def test_synchronize(self):
 
        synchronizer = sync.Synchronizer(self.local_engine, self.remote_engines)
 

	
 
        with patch.object(synchronizer, 'synchronize_changes') as synchronize_changes:
 

	
 
            # no changes
 
            synchronizer.synchronize()
 
            self.assertFalse(synchronize_changes.called)
0 comments (0 inline, 0 general)