Processes¶
Fugue is a new kind of operating system, designed to operate the distributed computer that we colloquially refer to as “the cloud.” The most obvious operating system feature of Fugue is the way it controls the execution of processes, which we refer to as Fugue’s “process management model.”
Understanding the Fugue Process Management Model¶
In summary, Fugue does all work in the form of processes.
What is a Fugue process?¶
A process is an instance of an infrastructure composition that the Conductor is working to build and maintain. Generally, a process can be thought of as a composition that will be “made so.” The Conductor takes a variety of actions to ensure that items in the composition exist and have the configuration declared therein. It does this both when the process is first run, and continuously while it is running.
In other words, a Ludwig composition is the code, whereas
the process represents the workload. A given composition may be
run more than once, resulting in multiple processes.
Processes and jobs¶
Processes consume Conductor compute time during jobs, where process data is reviewed and acted upon as necessary at regular intervals. Each job can potentially represent some change in the managed infrastructure, although most jobs are simply inspection and require no action. Jobs for multiple processes may be running at any given time.
How and whether jobs are emitted is dependent on process state. Valid
process states are Running, Suspended, and Killing.
Running is the most common state, where the process may be building
architecture, monitoring configuration, or otherwise doing what it’s
intended to do. Processes which are Killing are being cleaned up by
the current job, and processes which are Suspended do not emit jobs
until they are reactivated with a resume command.
Process states and transitions¶
The states and transitions in the Fugue process management model are summarized in the table below.
Commanded state transitions for Fugue processes
| ...to Running | ...to Suspended | ...to Killing | |
|---|---|---|---|
| From nothing... | run |
– | – |
| From Running... | – | suspend |
kill |
| From Suspended... | resume |
– | kill |
| From Killing... | – | suspend |
– |
Note that once a kill completes, a process cannot be restored and is
permanently deleted. However, you can simply run the same
composition again in a new process.
As you can see, there’s a pretty limited list of state transitions. The Fugue CLI Reference has some detail on how to make these transitions happen, but we’ll briefly review them as far as the internal impact they have.
From nothing to Running (fugue run)¶
The essential Fugue process state transition, this is what you’ll do to build things. This starts a new process, which creates jobs. The gist is that processes in this state create infrastructure and enforce its configuration.
From Running to Killing (fugue kill)¶
The inverse of a run. The gist of a kill state transition is that it results in the deletion of all infrastructure managed in the process.
From Suspended to Killing (fugue kill)¶
This state transition works the same as the Running to Killing transition, and has identical results: the deletion of all infrastructure managed in the process.
Just remember this: A kill command always kills the process,
whether its current state is Running or Suspended.
From Running to Suspended (fugue suspend)¶
This state transition keeps the process in “memory” in Fugue, but halts emitting new jobs. As such, no work is done on the process at all. This means nothing is created or destroyed, and all configuration enforcement stops while in this state.
Note that Running to Suspended is also the only uncommanded state
transition that may occur in Fugue. If a process encounters runtime
errors that require human review, decision, or intervention, the Fugue
runtime makes this transition. See the Fugue CLI Reference
chapter on the fugue status command to learn
how to get more information about a suspended process.
From Killing to Suspended (fugue suspend)¶
This state transition is similar to the transition from Running to
Suspended and typically occurs when a user wants to pause a kill.
(From here, the user can cancel the kill
by executing resume, or they may
continue the kill by executing kill
again.)
From Suspended to Running (fugue resume)¶
This state transition restores the process to the Running state, when it
again emits jobs. If configuration has been altered while in the
suspended state, but no update to the composition has occurred, any
such alterations are reverted.
You might intentionally make changes to a Suspended process in a
reliability testing scenario to simulate application response to
component failure, or even in production to mitigate an unanticipated
problem. When the dust has settled, you can then resume the process
to return it to its normal, declared state.
You may also have gotten here by executing suspend on a process in a
Killing state. From here, resume enables you to cancel the kill
and return to Running.
How many processes can a Fugue Conductor manage?¶
The upper bound on this is not yet determined, but the important bit of the answer is “more than one.” Like modern operating systems, Fugue handles more than one process at the same time.
How does Fugue handle the order of processes?¶
Fugue does not adhere to a particular order for processes and instead chooses to follow a natural order of AWS operations when evaluating and deciding how to process requests. For example: a subnet is never created before the VPC it belongs to. In short, Fugue completes all requests for a specific resource type before moving on to the next type for each process.
How does Fugue perform process work?¶
For each process, the Fugue Conductor performs all the steps required to make sure that the infrastructure exists (or is destroyed, in some cases) and is faithful to the configuration declared for it in a composition. To explain how this happens, let’s walk through a job.
First, there is a job.
Every thirty seconds, the Conductor’s scheduler emits a job for each process. This job prompts other components to begin work on the process.
Next, process and environment data are evaluated to construct a plan.
Conductor components perform work only for processes in the Running or Killing states since those are the only two states where processes emit jobs. Orchestrated by the Conductor’s manager, the components do work that roughly fits this sequence:
- Load a compiled composition into memory for reference. This tells all the components what the state of infrastructure should be.
- Examine the environment by interrogating infrastructure provider APIs. This tells all the components what the state of infrastructure actually is.
- Identify what differences exist between what should be and what actually is.
- Based on the information derived above, produce a plan of action for infrastructure changes, if they are required.
Finally, the plan is handled by the Conductor’s broker.
The plan of action produced during the job is handed off to the broker for execution. The broker ensures that the appropriate infrastructure changes are applied before reporting the job as a success to the scheduler.
Are there other ways work gets done in Fugue?¶
No. To remain easy to understand and reason about, Fugue does all work for a process in a job. This is even true for first-time builds of a brand-new process, as well as for tear-downs of long-running processes. Each is just a different case applied to the same function, in which Fugue works to close the difference between what you’ve said should be, and what is in the world. We can quickly step through the function and cases here.
The Fugue process as a Function¶
Consider the following as a crude definition of the work a Fugue process does, with a job representing invocation of this function.
Note
This advanced topic details how Fugue reasons about plans, and may be skipped by readers who want to jump right into building stuff with Fugue.
def fugueProcess (whatShouldBe, whatIs):
execute(plan(compare(whatShouldBe, whatIs)))
There are several child functions in the “stack” that we should understand:
compare(a, b), which compareswhatShouldBewithwhatIsand returns a delta;plan(d), which produces a plan to negate the delta, and;execute(p), which performs I/O to execute a plan.
Keep in mind that fugueProcess would be invoked for each process on
each job.
In the case of a new process:
Here, the inaugural job invokes fugueProcess where:
whatShouldBeis a composition defining infrastructure(A, B, C), and;whatIsis a report of the current infrastructure environment,().
Evaluation of compare shows that the difference between these sets
is (A, B, C).
Evaluation of plan produces a plan to add A, B, and C to
“What Is,” the infrastructure environment, (Make A, Make B, Make C).
Evaluation of execute adds A, B, and C to the
infrastructure environment. Now, “What Is” is in harmony with “What
Should Be.”
In the case of an established process:
Here, a job invokes fugueProcess where:
whatShouldBeis a composition defining infrastructure(A, B, C), and;whatIsis a report of the current infrastructure environment,(A, B, C).
Evaluation of compare shows that the difference between these sets
is ().
This is a fairly boring example, as the plan and execution
evaluations for an empty set produce no meaningful answer. It is worth
noting, however, that in a typical, static infrastructure environment,
this is overwhelmingly the most common case.
In the case of process enforcement or update:
Enforcement of configuration – in other words, the reversal of
configuration drift – and updates-in-place to a running process are
functionally identical. Consider the case of configuration drift, so
that we invoke fugueProcess where:
whatShouldBeis a composition defining infrastructure(A, B, C), and;whatIsis a report of the current infrastructure environment,(A, B, Z).
To take the function out of the abstract, think of C as a security
group, and Z as the same security group with a rule added allowing
TCP port 22 ingress from CIDR 0.0.0.0/0.
Evaluation of compare shows that the difference between these sets
is (C Became Z).
Evaluation of plan produces a plan to revert Z back to C in
the infrastructure environment, (Z Change-to C).
Evaluation of execute reconfigures Z to the declared
configuration, C. Your servers are no longer open to SSH from the
world.
A fugue update action produces a very similar case, where:
whatShouldBeis a composition defining infrastructure(Q, B, C), and;whatIsis a report of the current infrastructure environment,(A, B, C).
Following the same pattern as above, we expect the execution of the plan
(A Change-to Q).
Depending on the resource that is being changed, (A Change-to Q) may
be either a destructive update or a mutative update. A
destructive update is one in which the resource properties cannot be
changed, so instead the entire resource is destroyed and replaced with a
new one. A mutative update, on the other hand, is an update-in-place
for resource properties that can be changed – for example, VPC tags
or security group rules.
Think of A and Q as VPC tags. Let’s say A is my-old-tag
and Q is my-new-tag. A fugue update action resulting in
(A Change-to Q) would be a mutative update. The VPC’s tags
change, so the VPC itself is not destroyed.
Now, think of A and Q as VPC CIDR blocks. A is
10.0.0.0/16 and Q is 192.168.0.0/16. A fugue update
action resulting in (A Change-to Q) would be a destructive
update. The VPC’s CIDR block cannot change, so the VPC is destroyed and
replaced with a new one.
Resource properties that may be mutated rather than destroyed/replaced include the following:
- Virtual private cloud (VPC) tags
- VPC security group rules and tags
- Auto-scaling group (ASG) properties
Updates to any other resource are destructive.
In the case of a killed process:
When a process enters the Killing state, the job that is emitted
prompts a sequence of actions to clean up the resources declared in the
process composition. This is an inversion of the case of a new process,
where:
whatShouldBeis a special null composition,(), andwhatIsis a report of the current infrastructure environment,(A, B, C).
Evaluation of compare shows that the difference between these sets
is (A, B, C).
Evaluation of plan produces a plan to delete A, B, and C
from the infrastructure environment, (Delete A, Delete B, Delete C).
Evaluation of execute removes A, B, and C from the
infrastructure environment.
In the case of a suspended process:
As you’ve learned, a suspended process does not emit jobs, so the function is never invoked.