Skip to main content

Execution Order

Steps

Anemos uses a class called Step to sort actions flexibly. The Step class has a description (for logging) and a list of numbers.

When comparing two Step objects, the numbers in their respective lists are compared index by index. If one list is shorter than the other, missing numbers at higher indices are treated as 0 for comparison.

For example, comparing [1, 2] with [1]:

  1. Index 0: Both have 1. They are equal.
  2. Index 1: The first step has 2, the second has no number (treated as 0). Since 2 > 0, the first step [1, 2] is considered greater than the second step [1].

This system allows for fine-grained control over execution sequence. Consider these standard steps provided by Anemos:

  • generateResources: [5]
  • generateResourcesBasedOnOtherResources: [5, 1]
  • modify: [6]

Comparing these:

  • generateResources [5] is less than modify [6] because 5 < 6.
  • generateResourcesBasedOnOtherResources [5, 1] is greater than generateResources [5] because at index 1, 1 > 0.
  • generateResourcesBasedOnOtherResources [5, 1] is less than modify [6] because at index 0, 5 < 6.

This structure allows inserting custom steps between existing ones. For instance, a step like [5, 1, 1] would execute after [5, 1] but before [5, 2]. Similarly, [5, 0, 1] would run after [5] but before [5, 1].

Executing Actions

The Builder orchestrates the execution of actions. When you call the build() method:

  1. It collects all actions from all added components.
  2. It sorts these actions based on their assigned Step.
  3. It executes the actions sequentially in the sorted order.

Example: Execution Order in Practice

Consider the following example components:

index.ts
import * as anemos from "@ohayocorp/anemos";

class App1Component extends anemos.Component {
constructor() {
super();
this.addAction(anemos.steps.generateResources, this.generateResources);
}

generateResources = (context: anemos.BuildContext) => {
context.addDocument(
`app1-pod.yaml`,
`
apiVersion: v1
kind: Pod
metadata:
name: app1
labels:
app: app1
spec:
containers:
- name: app1
image: app1:latest
`);
};
}

class App2Component extends anemos.Component {
constructor() {
super();
this.addAction(anemos.steps.generateResources, this.generateResources);
}

generateResources = (context: anemos.BuildContext) => {
context.addDocument(
`app2-pod.yaml`,
`
apiVersion: v1
kind: Pod
metadata:
name: app2
labels:
app: app2
spec:
containers:
- name: app2
image: app2:latest
`);
};
}

class SetNodeNameComponent extends anemos.Component {
constructor() {
super();
this.addAction(anemos.steps.modify, this.modifyResources);
}

modifyResources = (context: anemos.BuildContext) => {
for (const document of context.getAllDocuments()) {
// Check if the document is a workload (e.g. Pod, Deployment, etc.) and skip if not.
if (!document.isWorkload()) {
continue;
}

// If the document does not have the label "app: app1", skip it.
if (document.getLabel("app") !== "app1") {
continue;
}

// Run app1 pods on node "worker-1".
document.ensureWorkloadSpec().set("nodeName", "worker-1");
}
};
}

const builder = new anemos.Builder("1.31", anemos.KubernetesDistribution.Minikube, anemos.EnvironmentType.Development);

builder.addComponent(new SetNodeNameComponent());
builder.addComponent(new App1Component());
builder.addComponent(new App2Component());

builder.build();

In this example:

  • App1Component adds an action with step generateResources.
  • App2Component adds an action with step generateResources.
  • SetNodeNameComponent adds an action with step modify.

When builder.build() is called:

  1. The actions are collected.
  2. They are ordered by their steps: generateResources [5] comes before modify [6].
  3. Execution proceeds:
    • The generateResources action from App1Component runs.
    • The generateResources action from App2Component runs.
    • The modify action from SetNodeNameComponent runs.

Even if SetNodeNameComponent was added to the builder before App1Component or App2Component, its modify action runs after their generateResources actions due to the defined Step ordering.

For actions that run during the same Step (like the two generateResources actions), their relative execution sequence is determined by the order in which their parent components were added to the Builder. Since App1Component was added first, its generateResources action runs before the one from App2Component.