Transfer optimization¶
By default, the Inmanta server performs a new compile every time the state of a service instance changes. However, in practice it often happens that a transition between two states doesn’t result in a new desired state for the service instance. To prevent unnecessary compiles, the LSM module has support to indicate which transfers in a lifecycle preserve the desired state. The Inmanta server can then use this information to improve the performance of state transitions. This page describes how to mark transfers in a lifecycle as state-preserving and how to enable the transfer optimization feature on the server.
Annotating desired state-preserving transfers¶
The lsm::StateTransfer
entity has two attributes to indicate that a transfer preserves the desired state:
bool target_same_desired_state (default=false): True iff following the success edge doesn’t change the desired state.
bool error_same_desired_state (default=false): True iff following the error edge doesn’t change the desired state.
The code snippet below models a lifecycle that contains state-preserving transfers:
1import lsm
2import lsm::fsm
3import std::testing
4
5start = lsm::State(
6 name="start",
7 export_resources=false,
8 validate_self="candidate",
9)
10creating = lsm::State(
11 name="creating",
12 export_resources=true,
13 validate_self="active",
14 validate_others="active",
15)
16up = lsm::State(
17 name="up",
18 label="success",
19 export_resources=true,
20 validate_self="active",
21 validate_others="active",
22)
23failed = lsm::State(
24 name="failed",
25 label="danger",
26 export_resources=true,
27 validate_self="active",
28 validate_others="active",
29)
30rejected = lsm::State(
31 name="rejected",
32 label="danger",
33 export_resources=false,
34 deleted=true,
35)
36deleting = lsm::State(
37 name="deleting",
38 export_resources=true,
39 validate_self="active",
40 validate_others="active",
41 purge_resources=true,
42)
43terminated = lsm::State(
44 name="terminated",
45 export_resources=false,
46 deleted=true,
47)
48
49basic_lifecycle = lsm::LifecycleStateMachine(
50 name="testing::basic_lifecycle",
51 initial_state=start,
52 transfers=[
53 lsm::StateTransfer(
54 source=start,
55 target=creating,
56 error=rejected,
57 validate=true,
58 auto=true,
59 target_operation="promote",
60 error_same_desired_state=true,
61 ),
62 lsm::StateTransfer(
63 source=creating,
64 target=up,
65 error=creating,
66 resource_based=true,
67 target_same_desired_state=true,
68 error_same_desired_state=true,
69 ),
70 lsm::StateTransfer(
71 source=up,
72 target=up,
73 error=failed,
74 resource_based=true,
75 target_same_desired_state=true,
76 error_same_desired_state=true,
77 ),
78 lsm::StateTransfer(
79 source=failed,
80 target=up,
81 error=failed,
82 resource_based=true,
83 target_same_desired_state=true,
84 error_same_desired_state=true,
85 ),
86 lsm::StateTransfer(
87 source=up,
88 target=deleting,
89 on_delete=true,
90 ),
91 lsm::StateTransfer(
92 source=deleting,
93 target=terminated,
94 error=deleting,
95 resource_based=true,
96 error_same_desired_state=true,
97 ),
98 ]
99)
Let’s discuss the transfers that are not marked as state-preserving and why:
start -> creating: Not a state-preserving transfer because it moves the instances from a non-exporting state to an exporting state.
up -> deleting: Not a state-preserving transfer because this state transfer flips the
purge_resources
flag, which will have an effect on the desired state being deployed.deleting -> terminated: Not a state-preserving transfer because it moves the instance from an exporting to a non-exporting state.
All other transfers were marked as state-preserving transfers. This decision was based on the assumption that not changing the high-level intent (active attribute set) doesn’t change the low-level intent (what is deployed to the infrastructure). This assumption doesn’t hold in all situations. The service model could for example change the low-level intent based on the current state of the service instance. Caution is advised when modelling a lifecycle with state-preserving transfer, as incorrectly marking a transfer as state-preserving will cause the orchestrator to behave incorrectly.
Enabling the transfer optimization feature¶
The environment setting enable_lsm_transfer_optimization
can be used to enable
the transfer optimization feature. When enabled, the LSM extension will perform a compile only when transitioning between
two states that don’t preserve the desired state. When disabled, a recompile will be done for each state transition.
Validation compiles are not impacted by this setting. They are always executed.
Testing¶
The Inmanta server validates every lifecycle that is exported to the server and it will reject any lifecycle that is
indisputably wrong. The server will for example reject lifecycles with state-preserving transfers
that connect a state that exports resources with a state that doesn’t export resources. However, the server cannot
exhaustively detect all cases where transfers are incorrectly marked as state-preserving. As such, it’s important to
add tests that validate whether the service model behaves consistently, whether or not the
enable_lsm_transfer_optimization
environment setting is enabled.