Copyright @ Lenovo US
This charm is created to demonstrate chained states using Juju charm. Chained states is essentially mirroring a pattern of any sequential execution in a workflow. Potentially each execution block can also have conditions to set the next state, even though this type of knowledge should be exposed outside function element, if possible, and to be handled by something better than pure code (eg. BPMN).
The model for this experiment is straightforward. We create a layer
with three states:
state.3. Upon start
charm kicks off execution of
state.1, which then transit itself to
state.2, then to
state.3, and then loop back to
The key questions to answer in this experiment are:
- What is the entry point to start the first state?
- If setting two states true, are they executed serially or in parallel?
- Can a blocking command halt state transition even if there are states being true and can be acted upon?
Top left window shows the
juju debug-log which prints state
transition among three states. Top right window
juju status also
shows state transitions in Message column which is set by
set_status in each state's function block.
The 1st state
How to start the first state?
In this test we experimented using hooks to introduce the first state since hooks
are executed in a predetermined sequence. However,
set_state has no
effect and actually should be avoided within hook execution according
to document (needs reference).
To safely start the whole process, we settled on
@only_once def state_0(): log('something------------------')
Chain state pattern
The three primary states follow the same pattern. Using
state.1 for example:
@when('state.1') def state_1(): """State.1 """ # set status t = time.ctime(time.time()) status_set('maintenance', 'state.1 %s' % t) # workload time.sleep(TEST_TIMEOUT) # state transition remove_state('state.1') set_state('state.2')
Multiple states being true
If we set multiple states
true, will they be executed in parallel?
From previous article on state execution, we can already see that states are first saved in a dictionary and then scanned by iterator. Therefore, there is no parallel computing built in the charm execution mechanism. Further, execution order of two states have no guarantee except they will all be done sooner or later because Python dictionary does not enforce any order.
truestates will be executed in serial. Orders of execution is undetermined.
Long running process
Will a shell blocking call halt state transition?
In this test we want to verify whether starting a long running process
will block charm's state transition. We used
start a blocking call while state 1-3 are kept to loop as designed.
def state_4(): """State4. """ subprocess.check_all("apt update && apt dist-upgrade")
The result is clear that state machine will come to a halt at this blocking call, which would have to be the case since we already know how states are being scanned and executed from previous article. All states are cached in a dictionary and are scanned in a tight loop per iteration. Thus a blocking call in any handler will cause the loop to a halt. Nowhere in code will take a signal so this behavior can not be interruptted either.
— by Feng Xia