commit 9b98703f246902820d71ee6f27273895edc8b484
parent 4be5325df217b5e664b5da323a4540cfcedb3666
Author: lash <dev@holbrook.no>
Date:   Sun,  1 May 2022 06:58:52 +0000
Receive race handling from chainqueue, rehabilitate tests
Diffstat:
7 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
@@ -1,3 +1,6 @@
+- 0.2.0
+	* primitive race condition handling between fs access of sync and queue
+	* re-enable throttling based on in-flight transaction count
 - 0.1.2
 	* add settings object
 - 0.1.0
diff --git a/chaind/adapters/base.py b/chaind/adapters/base.py
@@ -1,10 +1,28 @@
 # external imports
 from chainqueue import Store as QueueStore
 
+# local imports
+from chaind.error import BackendIntegrityError
+
 
 class ChaindAdapter:
 
+    race_delay = 0.1
+
     def __init__(self, chain_spec, state_store, index_store, counter_store, cache_adapter, dispatcher, cache=None, pending_retry_threshold=0, error_retry_threshold=0):
         self.cache_adapter = cache_adapter
         self.dispatcher = dispatcher
-        self.store = QueueStore(chain_spec, state_store, index_store, counter_store, cache=cache)
+        err = None
+        for i in range(3):
+            try:
+                self.store = QueueStore(chain_spec, state_store, index_store, counter_store, cache=cache)
+                err = None
+                break
+            except FileNotFoundError as e:
+                logg.debug('queuestore instantiation failed, possible race condition (will try again): {}'.format(tx_hash, e))
+                err = e
+                time.sleep(self.race_delay)
+                continue
+
+        if err != None:
+            raise BackendIntegrityError(err)
diff --git a/chaind/adapters/fs.py b/chaind/adapters/fs.py
@@ -10,12 +10,12 @@ from chainqueue.store.fs import (
         IndexStore,
         CounterStore,
         )
-from chainqueue.error import BackendIntegrityError
 from shep.store.file import SimpleFileStoreFactory
 from shep.error import StateInvalid
 
 # local imports
 from .base import ChaindAdapter
+from chaind.error import BackendIntegrityError
 
 logg = logging.getLogger(__name__)
 
@@ -38,13 +38,19 @@ class ChaindFsAdapter(ChaindAdapter):
 
     def get(self, tx_hash):
         v = None
-        try:
-            v = self.store.get(tx_hash)
-        except StateInvalid as e:
-            logg.error('I am just a simple syncer and do not know how to handle the state which the tx {} is in: {}'.format(tx_hash, e))
-            return None
-        except FileNotFoundError:
-            pass
+        err = None
+        for i in range(3):
+            try:
+                v = self.store.get(tx_hash)
+                err = None
+            except StateInvalid as e:
+                logg.error('I am just a simple syncer and do not know how to handle the state which the tx {} is in: {}'.format(tx_hash, e))
+                return None
+            except FileNotFoundError as e:
+                err = e
+                time.sleep(self.race_delay)
+                logg.debug('queuestore get {} failed, possible race condition (will try again): {}'.format(tx_hash, e))
+                continue
         if v ==None:
             raise BackendIntegrityError(tx_hash)
         return v[1]
@@ -52,7 +58,7 @@ class ChaindFsAdapter(ChaindAdapter):
 
     def upcoming(self, limit=0):
         real_limit = 0
-        in_flight = 0
+        in_flight = []
         if limit > 0:
             in_flight = self.store.by_state(state=self.store.IN_NETWORK, not_state=self.store.FINAL)
             real_limit = limit - len(in_flight)
diff --git a/chaind/error.py b/chaind/error.py
@@ -20,3 +20,7 @@ class ClientInputError(ValueError):
 
 class QueueLockError(Exception):
     pass
+
+
+class BackendIntegrityError(Exception):
+    pass
diff --git a/chaind/filter.py b/chaind/filter.py
@@ -5,14 +5,14 @@ import time
 # external imports
 from chainlib.status import Status as TxStatus
 from chainsyncer.filter import SyncFilter
-from chainqueue.error import (
-        NotLocalTxError,
-        BackendIntegrityError,
-        )
+from chainqueue.error import NotLocalTxError
 from chaind.adapters.fs import ChaindFsAdapter
 
 # local imports
-from .error import QueueLockError
+from .error import (
+        QueueLockError,
+        BackendIntegrityError,
+        )
 
 logg = logging.getLogger(__name__)
 
@@ -20,6 +20,7 @@ logg = logging.getLogger(__name__)
 class StateFilter(SyncFilter):
 
     delay_limit = 3.0
+    race_delay = 0.1
 
     def __init__(self, chain_spec, adapter_path, tx_adapter, throttler=None):
         self.chain_spec = chain_spec
@@ -41,6 +42,7 @@ class StateFilter(SyncFilter):
                     )
             except BackendIntegrityError as e:
                 logg.error('adapter instantiation failed: {}, one more try'.format(e))
+                time.sleep(self.race_delay)
                 continue
 
             try:
@@ -50,6 +52,7 @@ class StateFilter(SyncFilter):
                 return False
             except BackendIntegrityError as e:
                 logg.error('adapter instantiation failed: {}, one more try'.format(e))
+                time.sleep(self.race_delay)
                 continue
 
             break
diff --git a/setup.cfg b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = chaind
-version = 0.2.0
+version = 0.2.1
 description = Base package for chain queue service
 author = Louis Holbrook
 author_email = dev@holbrook.no
diff --git a/tests/test_fs.py b/tests/test_fs.py
@@ -74,7 +74,7 @@ class TestChaindFs(TestChaindFsBase):
         data = os.urandom(128).hex()
         hsh = self.adapter.put(data)
         
-        fltr = StateFilter(self.adapter)
+        fltr = StateFilter(self.chain_spec, self.path, MockCacheAdapter)
         tx = MockTx(hsh)
         fltr.filter(None, None, tx)
 
@@ -85,7 +85,7 @@ class TestChaindFs(TestChaindFsBase):
         data = os.urandom(128).hex()
         hsh = self.adapter.put(data)
         
-        fltr = StateFilter(self.adapter)
+        fltr = StateFilter(self.chain_spec, self.path, MockCacheAdapter)
         tx = MockTx(hsh, TxStatus.ERROR)
         fltr.filter(None, None, tx)