Here are some of the tips and trick I have learned when writing reactive charms. I have attached a simple bash example that helps illustrate the points in this email.
@hook decorators:
You almost never need @hook if you structure the reactive states correctly. I always have an "entry point" or a function that is called when no states are set (install_db2 in this example), and the function always sets the state when completing successfully. This function could be equivalent to the install hook, but is much better because removing the "[name].installed" state will cause the software to install again on the next reactive event cycle, where the install hook is only called on deploy and upgrade.
Immutability:
I normally have an "final state" that is always set when everything is complete. The reactive framework evaluates all the when and when_not decorators each time the states change, or a hook is run. So my "final state" function acts as a config-changed hook because the code will be run every time the reactive framework evaluates states. This helps so the code does not have immutable configuration. When configuration does change, I often just remove states and let the install or configure methods run again.
#!/bin/bash
source charms.reactive.sh
set -e
@when_not 'db2.installed'
function install_db2() {
local package_name=$(config-get 'db2_package_name')
local arch=$(uname -m)
# install DB2 here
set_state 'db2.installed'
}
@when 'db2.installed'
@when_not 'db2.configured'
function setup_db2() {
# Configure DB2 here.
set_state 'db2.configured'
}
@when 'db2.configured'
function configuration-changed() {
local package_name=$(config-get 'db2_package_name')
local current_package=$(/usr/bin/db2 --version)
# If the package changed remove the db2.installed state, that will cause a reinstall.
}
Here are some of the tips and trick I have learned when writing reactive charms. I have attached a simple bash example that helps illustrate the points.
@hook decorators:
You almost never need @hook if you structure the reactive states correctly. I always have an "entry point" or a function that is called when no states are set (the install_db2 function in this example), and the function always sets the "[name].installed" state when completing successfully. This function could be equivalent to the install hook, but is much better because removing the "[name].installed" state will cause the software to install again on the next reactive event cycle, where the install hook is only called on deploy and upgrade.
Immutability:
I normally have an "exit point" that is a state when everything completes successfully. The reactive framework evaluates all the states that match the @when and @when_not decorators each time a states changes, or any hook is run. So my "exit state" function acts as a config-changed hook because the code will be run every time the reactive framework evaluates states. This helps prevent immutable configuration in the charms. When configuration does change, I often just remove states and that makes the install or configure methods run again, depending on the situation.
You can of course make as many states and functions as makes sense for your code, but these are the basic ones that I start with on each charm.
Please email me if you have any questions.