Fix race condition in reload_on_sighup functional
Race condition appears in next situation:
1. First thread calls _set_config_value for one section.
2. Second thread calls _set_config_value for another section.
3. First thread. Config option value set, calls
open(self.config_file, 'wb'), which erases all file content.
4. Second thread. In previous point moment second thread tries to
set config option value to self.config_file, which is empty (see 3).
So, NoSectionError exception raised.
This patch adds ten retries for setting option value, if NoSectionError
raised, i.e. try to wait until self.config_file is busy.
Change-Id: Ic54ea287ebe4724511f75d42677cae5dfdec4e57
Closes-bug: #1535766
diff --git a/functional/test_reload_on_sighup.py b/functional/test_reload_on_sighup.py
index cba5386..b014f49 100644
--- a/functional/test_reload_on_sighup.py
+++ b/functional/test_reload_on_sighup.py
@@ -28,8 +28,27 @@
def _set_config_value(self, service, key, value):
config = configparser.ConfigParser()
- config.read(self.config_file)
- config.set(service, key, value)
+
+ # NOTE(prazumovsky): If there are several workers, there can be
+ # situation, when one thread opens self.config_file for writing
+ # (so config_file erases with opening), in that moment other thread
+ # intercepts to this file and try to set config option value, i.e.
+ # write to file, which is already erased by first thread, so,
+ # NoSectionError raised. So, should wait until first thread writes to
+ # config_file.
+ retries_count = self.conf.sighup_config_edit_retries
+ while True:
+ config.read(self.config_file)
+ try:
+ config.set(service, key, value)
+ except configparser.NoSectionError:
+ if retries_count <= 0:
+ raise
+ retries_count -= 1
+ eventlet.sleep(1)
+ else:
+ break
+
with open(self.config_file, 'wb') as f:
config.write(f)