Reentrant call to build_filterset()
what I mean by reentrant is:
def foo():
print("Enter foo")
print_callstack()
print("Exit foo")
executing foo in the context of Bliss/gevent would give the following trace:
Enter foo
> /home/blissadm/local/context1...
> /home/blissadm/local/bliss.git/bliss/bar.py(380)foo()
Enter foo
> /home/blissadm/local/context2...
> /home/blissadm/local/bliss.git/bliss/bar.py(380)foo()
Exit Foo
Exit Foo
The function foo
is called while a first call is being executed (and suspended due to some async operation).
In the autof framework, this is sometime the case (depending on the timing) with the build_filterset()
function at initialization of the session:
/home/blissadm/local/bliss2.git/bliss/config/channels.py(529)query_task()
-> self._set_raw_value(reply_value)
/home/blissadm/local/bliss2.git/bliss/config/channels.py(511)_set_raw_value()
-> self._fire_callbacks()
/home/blissadm/local/bliss2.git/bliss/config/channels.py(563)_fire_callbacks()
-> callback_exec.callback(cb, value)
/users/blissadm/conda/miniconda/envs/bliss_2_0/lib/python3.9/contextlib.py(517)__exit__()
-> if cb(*exc_details):
/users/blissadm/conda/miniconda/envs/bliss_2_0/lib/python3.9/contextlib.py(405)_exit_wrapper()
-> callback(*args, **kwds)
/home/blissadm/local/bliss2.git/bliss/common/motor_settings.py(32)setting_update_from_channel()
-> event.send_safe(axis, setting_name, value)
/home/blissadm/local/bliss2.git/bliss/common/event.py(35)send_safe()
-> return send(*args, **kwargs)
/home/blissadm/local/bliss2.git/bliss/common/event.py(25)send()
-> dispatcher.send(signal, sender, *args, **kwargs)
/users/blissadm/conda/miniconda/envs/bliss_2_0/lib/python3.9/site-packages/louie/dispatcher.py(343)send()
-> response = robustapply.robust_apply(
/users/blissadm/conda/miniconda/envs/bliss_2_0/lib/python3.9/site-packages/louie/robustapply.py(57)robust_apply()
-> return receiver(*arguments, **named)
/home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset.py(231)_update_all_from_energy_state_change()
-> self._update_all()
/home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset.py(274)_update_all()
-> self._nb_filters = self.build_filterset(list(self.__enabled_filters))
> /home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset_blade.py(380)build_filterset()
-> combinations = [[None, foil] for foil in self.active_foils]
-> return self._get(name)
/home/blissadm/local/bliss2.git/bliss/config/static.py(1077)_get()
-> for name2itemsAndname2itemcache in iteration:
/home/blissadm/local/bliss2.git/bliss/config/plugins/generic.py(506)create_objects_from_config_node()
-> bctrl = klass(item_name, cfg_node.clone())
/home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset_blade.py(227)__init__()
-> super().__init__(name, config)
/home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset.py(213)__init__()
-> self._update_all()
/home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset.py(274)_update_all()
-> self._nb_filters = self.build_filterset(list(self.__enabled_filters))
> /home/blissadm/local/bliss2.git/bliss/common/auto_filter/filterset_blade.py(380)build_filterset()
-> combinations = [[None, foil] for foil in self.active_foils]
The build_filterset()
is called in the context of
create_objects_from_config_node()
-
setting_update_from_channel()
from Redis via louie's event.
Let's call this the Redis Boomerang Effect (Reboom™ for short).
Unfortunately the build_filterset()
is not pure (e.g. has side-effects). The fix is trivial: the connection to the louie event (to get the energy axis updates) should be made after the first call to build_filterset() has completed.
But, in the general case, is there a pattern to avoid the Reboom™?