#59 fix threading issue with profiles
Merged 7 years ago by mikem. Opened 7 years ago by mikem.
https://github.com/mikem23/koji-playground.git profile_thread  into  master

acquire import lock in get_profile_module
Mike McLean • 7 years ago  
add unit test for using profiles in threads
Mike McLean • 7 years ago  
hub/__init__.py
file added
empty or binary file added
koji/__init__.py
file modified
+24 -18
@@ -1578,24 +1578,30 @@

      # Prepare module name

      mod_name = "__%s__%s" % (__name__, profile_name)

  

-     # Check if profile module exists and if so return it

-     if mod_name in PROFILE_MODULES:

-         return PROFILE_MODULES[mod_name]

- 

-     # Load current module under a new name

-     koji_module_loc = imp.find_module(__name__)

-     mod = imp.load_module(mod_name,

-                           None,

-                           koji_module_loc[1],

-                           koji_module_loc[2])

- 

-     # Tweak config of the new module

-     mod.config = config

-     mod.BASEDIR = config.topdir

-     mod.pathinfo.topdir = config.topdir

- 

-     # Be sure that get_profile_module is only called from main module

-     mod.get_profile_module = get_profile_module

+     imp.acquire_lock()

+     try:

+         # Check if profile module exists and if so return it

+         if mod_name in PROFILE_MODULES:

+             return PROFILE_MODULES[mod_name]

+ 

+         # Load current module under a new name

+         koji_module_loc = imp.find_module(__name__)

+         mod = imp.load_module(mod_name,

+                               None,

+                               koji_module_loc[1],

+                               koji_module_loc[2])

+ 

+         # Tweak config of the new module

+         mod.config = config

+         mod.BASEDIR = config.topdir

+         mod.pathinfo.topdir = config.topdir

+ 

+         # Be sure that get_profile_module is only called from main module

+         mod.get_profile_module = get_profile_module

+ 

+         PROFILE_MODULES[mod_name] = mod

+     finally:

+         imp.release_lock()

  

      return mod

  

tests/test_profiles.py
file added
+41
@@ -0,0 +1,41 @@

+ import unittest

+ 

+ import koji

+ import sys

+ import threading

+ import traceback

+ 

+ 

+ class ProfilesTestCase(unittest.TestCase):

+ 

+     def test_profile_threading(self):

+         """ Test that profiles thread safe"""

+         # see: https://pagure.io/koji/issue/58 and https://pagure.io/pungi/issue/253

+         # loop a few times to increase chances of hitting race conditions

+         for i in range(20):

+             errors = {}

+             threads = [threading.Thread(target=stress, args=(errors, _)) for _ in xrange(100)]

+             for t in threads:

+                 t.start()

+             for t in threads:

+                 t.join(30)

+             for n in errors:

+                 err = errors[n]

+                 if err is not None:

+                     print err

+                     assert False

+ 

+ 

+ def stress(errors, n):

+     errors[n] = "Failed to start"

+     try:

+         koji.get_profile_module('koji')

+     except Exception:

+         # if we don't catch this, nose seems to ignore the test

+         errors[n] = ''.join(traceback.format_exception(*sys.exc_info()))

+         return

+     else:

+         errors[n] = None

+ 

+ 

+ 

no initial comment

Pull-Request has been rebased

7 years ago

Pull-Request has been merged by mikem

7 years ago