1212# limitations under the License.
1313
1414import abc
15+ import numbers
1516import requests
1617import threading
1718import time
@@ -95,6 +96,7 @@ def __init__(self,
9596 notification_center = notification_center )
9697 self ._config = None
9798 self .validate_schema = not skip_json_validation
99+ self ._config_ready_event = threading .Event ()
98100 self ._set_config (datafile )
99101
100102 def _set_config (self , datafile ):
@@ -133,6 +135,7 @@ def _set_config(self, datafile):
133135 return
134136
135137 self ._config = config
138+ self ._config_ready_event .set ()
136139 self .notification_center .send_notifications (enums .NotificationTypes .OPTIMIZELY_CONFIG_UPDATE )
137140 self .logger .debug (
138141 'Received new datafile and updated config. '
@@ -145,6 +148,7 @@ def get_config(self):
145148 Returns:
146149 ProjectConfig. None if not set.
147150 """
151+
148152 return self ._config
149153
150154
@@ -155,6 +159,7 @@ def __init__(self,
155159 sdk_key = None ,
156160 datafile = None ,
157161 update_interval = None ,
162+ blocking_timeout = None ,
158163 url = None ,
159164 url_template = None ,
160165 logger = None ,
@@ -168,6 +173,8 @@ def __init__(self,
168173 datafile: Optional JSON string representing the project.
169174 update_interval: Optional floating point number representing time interval in seconds
170175 at which to request datafile and set ProjectConfig.
176+ blocking_timeout: Optional Time in seconds to block the get_config call until config object
177+ has been initialized.
171178 url: Optional string representing URL from where to fetch the datafile. If set it supersedes the sdk_key.
172179 url_template: Optional string template which in conjunction with sdk_key
173180 determines URL from where to fetch the datafile.
@@ -187,6 +194,7 @@ def __init__(self,
187194 self .datafile_url = self .get_datafile_url (sdk_key , url ,
188195 url_template or enums .ConfigManager .DATAFILE_URL_TEMPLATE )
189196 self .set_update_interval (update_interval )
197+ self .set_blocking_timeout (blocking_timeout )
190198 self .last_modified = None
191199 self ._polling_thread = threading .Thread (target = self ._run )
192200 self ._polling_thread .setDaemon (True )
@@ -224,15 +232,26 @@ def get_datafile_url(sdk_key, url, url_template):
224232
225233 return url
226234
235+ def get_config (self ):
236+ """ Returns instance of ProjectConfig. Returns immediately if project config is ready otherwise
237+ blocks maximum for value of blocking_timeout in seconds.
238+
239+ Returns:
240+ ProjectConfig. None if not set.
241+ """
242+
243+ self ._config_ready_event .wait (self .blocking_timeout )
244+ return self ._config
245+
227246 def set_update_interval (self , update_interval ):
228247 """ Helper method to set frequency at which datafile has to be polled and ProjectConfig updated.
229248
230249 Args:
231250 update_interval: Time in seconds after which to update datafile.
232251 """
233- if not update_interval :
252+ if update_interval is None :
234253 update_interval = enums .ConfigManager .DEFAULT_UPDATE_INTERVAL
235- self .logger .debug ('Set config update interval to default value {}.' .format (update_interval ))
254+ self .logger .debug ('Setting config update interval to default value {}.' .format (update_interval ))
236255
237256 if not isinstance (update_interval , (int , float )):
238257 raise optimizely_exceptions .InvalidInputException (
@@ -249,6 +268,31 @@ def set_update_interval(self, update_interval):
249268
250269 self .update_interval = update_interval
251270
271+ def set_blocking_timeout (self , blocking_timeout ):
272+ """ Helper method to set time in seconds to block the config call until config has been initialized.
273+
274+ Args:
275+ blocking_timeout: Time in seconds to block the config call.
276+ """
277+ if blocking_timeout is None :
278+ blocking_timeout = enums .ConfigManager .DEFAULT_BLOCKING_TIMEOUT
279+ self .logger .debug ('Setting config blocking timeout to default value {}.' .format (blocking_timeout ))
280+
281+ if not isinstance (blocking_timeout , (numbers .Integral , float )):
282+ raise optimizely_exceptions .InvalidInputException (
283+ 'Invalid blocking timeout "{}" provided.' .format (blocking_timeout )
284+ )
285+
286+ # If blocking timeout is less than 0 then set it to default blocking timeout.
287+ if blocking_timeout < 0 :
288+ self .logger .debug ('blocking timeout value {} too small. Defaulting to {}' .format (
289+ blocking_timeout ,
290+ enums .ConfigManager .DEFAULT_BLOCKING_TIMEOUT )
291+ )
292+ blocking_timeout = enums .ConfigManager .DEFAULT_BLOCKING_TIMEOUT
293+
294+ self .blocking_timeout = blocking_timeout
295+
252296 def set_last_modified (self , response_headers ):
253297 """ Looks up and sets last modified time based on Last-Modified header in the response.
254298
0 commit comments