Browse Source

Fix verification procedure freezing on Citrine (#5208)

* [ci skip] try to fix siege command blocking

see https://github.com/TechEmpower/FrameworkBenchmarks/pull/5145

* python 2.7 version (no timeout for subprocess)

* add PopenTimeout class

* [ci skip] Remove unused methods

* try all systems version

* Increase timeout (20s)
jcheron 5 years ago
parent
commit
b7286c2c37
2 changed files with 52 additions and 5 deletions
  1. 9 5
      toolset/databases/abstract_database.py
  2. 43 0
      toolset/utils/popen.py

+ 9 - 5
toolset/databases/abstract_database.py

@@ -1,6 +1,8 @@
 import abc
-import commands
 import re
+import shlex
+import subprocess
+from toolset.utils.popen import PopenTimeout
 
 class AbstractDatabase:
     '''
@@ -86,15 +88,17 @@ class AbstractDatabase:
             rows_updated = int(cls.get_rows_updated(config))
 
         cls.reset_cache(config)
-        #Start siege requests
+        #Start siege requests with timeout (20s)
         path = config.db_root
-        output = commands.getoutput("siege -c %s -r %s %s -R %s/.siegerc" % (concurrency, count, url, path))
-        print output
-
+        process = PopenTimeout(shlex.split("siege -c %s -r %s %s -R %s/.siegerc" % (concurrency, count, url, path)), stdout = subprocess.PIPE, stderr = subprocess.STDOUT, timeout=20)
+        output, _ = process.communicate()
         #Search for failed transactions
         match = re.search('Failed transactions:.*?(\d+)\n', output, re.MULTILINE)
         if match:
             trans_failures = int(match.group(1))
+            print output
+        else:
+            trans_failures = concurrency * count#Failed transactions: 100%
 
         queries = int(cls.get_queries(config)) - queries
         rows = int(cls.get_rows(config)) - rows

+ 43 - 0
toolset/utils/popen.py

@@ -0,0 +1,43 @@
+from logging import error
+from subprocess import Popen
+from threading import Event
+from threading import Thread
+
+class PopenTimeout(Popen):
+    '''
+    Popen class with timeout for Python 2.7
+    see https://stackoverflow.com/questions/1191374/using-module-subprocess-with-timeout
+    '''
+    def __init__(self, *args, **kwargs):
+        self.timeout = kwargs.pop('timeout', 0)
+        self.timer = None
+        self.done = Event()
+
+        Popen.__init__(self, *args, **kwargs)
+
+    def __tkill(self):
+        timeout = self.timeout
+        if not self.done.wait(timeout):
+            error('Terminating process {} by timeout of {} secs.'.format(self.pid, timeout))
+            self.kill()
+
+    def expirable(func):
+        def wrapper(self, *args, **kwargs):
+            # zero timeout means call of parent method
+            if self.timeout == 0:
+                return func(self, *args, **kwargs)
+
+            # if timer is None, need to start it
+            if self.timer is None:
+                self.timer = thr = Thread(target=self.__tkill)
+                thr.daemon = True
+                thr.start()
+
+            result = func(self, *args, **kwargs)
+            self.done.set()
+
+            return result
+        return wrapper
+
+    wait = expirable(Popen.wait)
+    communicate = expirable(Popen.communicate)