Closed InterLinked1 closed 1 month ago
cherry-pick-to: 18 cherry-pick-to: 20 cherry-pick-to: 21
This PR has been marked stale because it has been in "Changes Requested" or "submitter-action-required" state for 28 days or more. Please make the requested changes within 14 days or the PR will be closed.
This PR has been marked stale because it has been in "Changes Requested" or "submitter-action-required" state for 28 days or more. Please make the requested changes within 14 days or the PR will be closed.
I lost track of this one, sorry. I'm reviewing today.
@InterLinked1 Do you have an example of a module that actually can be refreshed recursively? Every one I've tried gets Soft unload failed ...
@InterLinked1 Do you have an example of a module that actually can be refreshed recursively? Every one I've tried gets
Soft unload failed ...
Most of my use cases are my own proprietary modules with layered dependencies, but I found one that should work in a stock install - this appears to be two layers since app_mixmonitor
depends on func_periodic_hook
and func_periodic_hook
depends on func_cut
:
Here it is originally:
debian*CLI> module refresh func_cut automatically
Unloaded and loaded func_cut
[2024-04-27 10:24:37.446] Unloading app_mixmonitor.so
[2024-04-27 10:24:37.447] == Unregistered application 'StopMixMonitor'
[2024-04-27 10:24:37.447] == Unregistered application 'MixMonitor'
[2024-04-27 10:24:37.447] == Manager unregistered action MixMonitorMute
[2024-04-27 10:24:37.447] == Manager unregistered action MixMonitor
[2024-04-27 10:24:37.447] == Manager unregistered action StopMixMonitor
[2024-04-27 10:24:37.447] == Unregistered custom function MIXMONITOR
[2024-04-27 10:24:37.447] Unloading func_periodic_hook.so
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/3, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/4, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/5, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/6, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/beep/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/beep/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[2024-04-27 10:24:37.447] == Unregistered custom function PERIODIC_HOOK
[2024-04-27 10:24:37.447] Unloading func_cut.so
[2024-04-27 10:24:37.447] == Unregistered custom function CUT
[2024-04-27 10:24:37.447] == Unregistered custom function SORT
[2024-04-27 10:24:37.447] == Registered custom function 'CUT'
[2024-04-27 10:24:37.447] == Registered custom function 'SORT'
[2024-04-27 10:24:37.447] Loaded func_cut.so => (Cut out information from a string)
[2024-04-27 10:24:37.447] == Registered custom function 'PERIODIC_HOOK'
[2024-04-27 10:24:37.447] Loaded func_periodic_hook.so => (Periodic dialplan hooks.)
[2024-04-27 10:24:37.447] == Registered application 'MixMonitor'
[2024-04-27 10:24:37.447] == Registered application 'StopMixMonitor'
[2024-04-27 10:24:37.447] == Manager registered action MixMonitorMute
[2024-04-27 10:24:37.447] == Manager registered action MixMonitor
[2024-04-27 10:24:37.447] == Manager registered action StopMixMonitor
[2024-04-27 10:24:37.447] == Registered custom function 'MIXMONITOR'
[2024-04-27 10:24:37.447] Loaded app_mixmonitor.so => (Mixed Audio Monitoring Application)
debian*CLI>
And now:
proliant*CLI> module refresh func_cut recursively
Unloaded and loaded func_cut
[Apr 27 10:43:43] > Unloading app_mixmonitor.so
[Apr 27 10:43:43] > Unregistered application 'StopMixMonitor'
[Apr 27 10:43:43] > Unregistered application 'MixMonitor'
[Apr 27 10:43:43] > Manager unregistered action MixMonitorMute
[Apr 27 10:43:43] > Manager unregistered action MixMonitor
[Apr 27 10:43:43] > Manager unregistered action StopMixMonitor
[Apr 27 10:43:43] > Unregistered custom function MIXMONITOR
[Apr 27 10:43:43] > Unloading func_periodic_hook.so
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/beep/3, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/beep/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/beep/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/6, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/5, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/4, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/3, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil)
[Apr 27 10:43:43] > Unregistered custom function PERIODIC_HOOK
[Apr 27 10:43:43] > Unloading func_cut.so
[Apr 27 10:43:43] > Unregistered custom function CUT
[Apr 27 10:43:43] > Unregistered custom function SORT
[Apr 27 10:43:43] > Registered custom function 'CUT'
[Apr 27 10:43:43] > Registered custom function 'SORT'
[Apr 27 10:43:43] > Loaded func_cut.so => (Cut out information from a string)
[Apr 27 10:43:43] > Registered custom function 'PERIODIC_HOOK'
[Apr 27 10:43:43] > Loaded func_periodic_hook.so => (Periodic dialplan hooks.)
[Apr 27 10:43:43] > Registered application 'MixMonitor'
[Apr 27 10:43:43] > Registered application 'StopMixMonitor'
[Apr 27 10:43:43] > Manager registered action MixMonitorMute
[Apr 27 10:43:43] > Manager registered action MixMonitor
[Apr 27 10:43:43] > Manager registered action StopMixMonitor
[Apr 27 10:43:43] > Registered custom function 'MIXMONITOR'
[Apr 27 10:43:43] > Loaded app_mixmonitor.so => (Mixed Audio Monitoring Application)
@InterLinked1 Do you have an example of a module that actually can be refreshed recursively? Every one I've tried gets
Soft unload failed ...
Most of my use cases are my own proprietary modules with layered dependencies, but I found one that should work in a stock install - this appears to be two layers since
app_mixmonitor
depends onfunc_periodic_hook
andfunc_periodic_hook
depends onfunc_cut
:Here it is originally:
debian*CLI> module refresh func_cut automatically Unloaded and loaded func_cut [2024-04-27 10:24:37.446] Unloading app_mixmonitor.so [2024-04-27 10:24:37.447] == Unregistered application 'StopMixMonitor' [2024-04-27 10:24:37.447] == Unregistered application 'MixMonitor' [2024-04-27 10:24:37.447] == Manager unregistered action MixMonitorMute [2024-04-27 10:24:37.447] == Manager unregistered action MixMonitor [2024-04-27 10:24:37.447] == Manager unregistered action StopMixMonitor [2024-04-27 10:24:37.447] == Unregistered custom function MIXMONITOR [2024-04-27 10:24:37.447] Unloading func_periodic_hook.so [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/3, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/4, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/5, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/hook/6, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/beep/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] -- Remove __func_periodic_hook_context__/beep/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [2024-04-27 10:24:37.447] == Unregistered custom function PERIODIC_HOOK [2024-04-27 10:24:37.447] Unloading func_cut.so [2024-04-27 10:24:37.447] == Unregistered custom function CUT [2024-04-27 10:24:37.447] == Unregistered custom function SORT [2024-04-27 10:24:37.447] == Registered custom function 'CUT' [2024-04-27 10:24:37.447] == Registered custom function 'SORT' [2024-04-27 10:24:37.447] Loaded func_cut.so => (Cut out information from a string) [2024-04-27 10:24:37.447] == Registered custom function 'PERIODIC_HOOK' [2024-04-27 10:24:37.447] Loaded func_periodic_hook.so => (Periodic dialplan hooks.) [2024-04-27 10:24:37.447] == Registered application 'MixMonitor' [2024-04-27 10:24:37.447] == Registered application 'StopMixMonitor' [2024-04-27 10:24:37.447] == Manager registered action MixMonitorMute [2024-04-27 10:24:37.447] == Manager registered action MixMonitor [2024-04-27 10:24:37.447] == Manager registered action StopMixMonitor [2024-04-27 10:24:37.447] == Registered custom function 'MIXMONITOR' [2024-04-27 10:24:37.447] Loaded app_mixmonitor.so => (Mixed Audio Monitoring Application) debian*CLI>
And now:
proliant*CLI> module refresh func_cut recursively Unloaded and loaded func_cut [Apr 27 10:43:43] > Unloading app_mixmonitor.so [Apr 27 10:43:43] > Unregistered application 'StopMixMonitor' [Apr 27 10:43:43] > Unregistered application 'MixMonitor' [Apr 27 10:43:43] > Manager unregistered action MixMonitorMute [Apr 27 10:43:43] > Manager unregistered action MixMonitor [Apr 27 10:43:43] > Manager unregistered action StopMixMonitor [Apr 27 10:43:43] > Unregistered custom function MIXMONITOR [Apr 27 10:43:43] > Unloading func_periodic_hook.so [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/beep/3, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/beep/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/beep/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/6, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/5, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/4, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/3, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/2, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Remove __func_periodic_hook_context__/hook/1, registrar=func_periodic_hook; con=<nil>((nil)); con->root=(nil) [Apr 27 10:43:43] > Unregistered custom function PERIODIC_HOOK [Apr 27 10:43:43] > Unloading func_cut.so [Apr 27 10:43:43] > Unregistered custom function CUT [Apr 27 10:43:43] > Unregistered custom function SORT [Apr 27 10:43:43] > Registered custom function 'CUT' [Apr 27 10:43:43] > Registered custom function 'SORT' [Apr 27 10:43:43] > Loaded func_cut.so => (Cut out information from a string) [Apr 27 10:43:43] > Registered custom function 'PERIODIC_HOOK' [Apr 27 10:43:43] > Loaded func_periodic_hook.so => (Periodic dialplan hooks.) [Apr 27 10:43:43] > Registered application 'MixMonitor' [Apr 27 10:43:43] > Registered application 'StopMixMonitor' [Apr 27 10:43:43] > Manager registered action MixMonitorMute [Apr 27 10:43:43] > Manager registered action MixMonitor [Apr 27 10:43:43] > Manager registered action StopMixMonitor [Apr 27 10:43:43] > Registered custom function 'MIXMONITOR' [Apr 27 10:43:43] > Loaded app_mixmonitor.so => (Mixed Audio Monitoring Application)
By the way, I really don't like how all the above log messages are "flat" hierarchy. I brought this up during your PR adjusting those, but I'm realizing now that I think at verbose levels 5 and above, there is no visual distinction between log messages.
I'm going to propose differentiating them somehow, to address this, though that's a separate issue.
Successfully merged to branch master and cherry-picked to ["18","20","21"]
Because of the (often recursive) nature of module dependencies in Asterisk, hot swapping a module on the fly is cumbersome if a module is depended on by other modules. Currently, dependencies must be popped manually by unloading dependents, unloading the module of interest, and then loading modules again in reverse order.
To make this easier, the ability to do this automatically in certain circumstances has been added, as an optional extension to the "module refresh" command. If requested, Asterisk will check if a module that has a positive usecount could be unloaded safely if anything recursively dependent on it were unloaded. If so, it will go ahead and unload all these modules and load them back again. This makes hot swapping modules that provide dependencies much easier.
Resolves: #474
UserNote: Modules with dependency relations can have their dependents automatically unloaded and loaded again using the "module refresh" CLI command or the ModuleLoad AMI command.