Preflight and Inflight
This content is also available in an interactive tutorial
One of the main differences between Wing and other languages is that it unifies both infrastructure definitions and application logic under the same programming model. This is enabled by the concepts of the preflight and inflight execution phases:
- Preflight: Code that runs once, at compile time, and generates the infrastructure configuration of your cloud application. For example, setting up databases, queues, storage buckets, API endpoints, etc.
- Inflight: Code that runs at runtime and implements your application's behavior. For example, handling API requests, processing queue messages, etc. Inflight code can be executed on various compute platforms in the cloud, such as function services (such as AWS Lambda or Azure Functions), containers (such as ECS or Kubernetes), VMs or even physical servers.
Preflight code
Your preflight code runs once, at compile time, and defines your application's infrastructure configuration. This configuration is then consumed by an infrastructure provisioning engine such as Terraform, CloudFormation, Pulumi or Kubernetes.
For example, this code snippet defines a storage bucket using a class from the standard library:
bring cloud;
let bucket = new cloud.Bucket();
There is no special annotation to define that this is preflight code because preflight is Wing's default execution phase.
Compiling the program with the Wing CLI will synthesize the configuration files which can be used to create the bucket and initialize its contents on a cloud provider.
Preflight code can be also used to configure services or set up more complex event listeners.
In this code snippet, we've specified the bucket's contents will be publicly accessible, and it will be pre-populated with a file during the app's deployment (not while the app is running).
bring cloud;
let bucket = new cloud.Bucket(public: true);
bucket.addObject("file1.txt", "Hello world!");
There are a few global functions with specific behaviors in preflight.
For example, adding a log()
statement to your preflight code will result in Wing printing a message to the console after compilation.
// hello.w
log("7 * 6 = {7 * 6}");
$ wing compile hello.w
7 * 6 = 42
Likewise, assert()
statements can be evaluated during preflight, and will cause compilation to fail if the assertion fails.
// hello.w
assert(2 + 2 == 5);
$ wing compile hello.w
error: assertion failed: 2 + 2 == 5
Inflight code
Inflight blocks are where you write asynchronous runtime code that can directly interact with resources through their inflight APIs. Inflight functions can be easily packaged and executed onto compute platforms like containers, CI/CD pipelines or FaaS. Inflight code can also be executed multiple times and on different machines in parallel.
Let's walk through some examples.
Inflight code is always contained inside a block that starts with the word inflight
.
let greeting = inflight () => {
log("Hello from the cloud!");
};
Inflight code can call other inflight functions and methods.
For example, cloud.Bucket
has an inflight method named list()
that can be called inside inflight contexts:
bring cloud;
let bucket = new cloud.Bucket();
let firstObject = inflight (): str => {
let items = bucket.list();
return items.at(0);
};
Even though bucket
is defined in preflight, it's okay to use its inflight method in inflight code because it will always refer to the same bucket "instance" after deployment.