When executing your template, CloudFormation will automatically work out which resources depend on each other and order their creation accordingly. Additionally, resource creation is parallelized as much as possible so that your stack execution finishes in the timeliest manner possible.
Let's look at an example where an app server depends on a DB server. To connect to the database, the app server needs to know its IP address or hostname. This situation would actually require you to create the DB server first so that you can use Ref to fetch its IP and provide it to your app server. CloudFormation has no way of knowing about the coupling between these two resources, so it will go ahead and create them in any order it pleases (or in parallel, if possible).
To fix this situation, we use the DependsOn attribute to tell CloudFormation that our app server depends on our DB server. In fact, DependsOn can actually take a list of strings if a resource happens to depend on multiple resources before it can be created. So, if our app server were to also depend on, say, a Memcached server, then we would use DependsOn to declare both dependencies.
If necessary, you can take this further. Let's say that, after your DB server boots, it will automatically start the database, set up a schema, and import a large amount of data. It may be necessary to wait for this process to complete before we create an app server that attempts to connect to a DB expecting a complete schema and dataset. In this scenario, we want a way to signal to CloudFormation that the DB server has completed its initialization so that it can go ahead and create resources that depend on it. This is where WaitCondition and WaitConditionHandle come in.
First, you create an AWS::CloudFormation::WaitConditionHandle type, which you can later reference via Ref.
Next, you create an AWS::CloudFormation::WaitCondition type. In our case, we want the waiting period to start as soon as the DB server is created, so we specify that this WaitCondition resource DependsOn our DB server.
After the DB server has finished importing data and is ready to accept connections, it calls the callback URL provided by the WaitConditionHandle resource to signal to CloudFormation that it can stop waiting and start executing the rest of the CloudFormation stack. The URL is supplied to the DB server via UserData, again using Ref. Typically, curl, wget, or some equivalent is used to call the URL.
A WaitCondition resource can have a Timeout period too. This is a value that's specified in seconds. In our example, we might supply a value of 900 because we know that it should never take more than 15 minutes to boot our DB and import the data.
Here's an example of what DependsOn, WaitConditionHandle, and WaitCondition look like when combined:
ExampleWaitHandle:
Type: AWS::CloudFormation::WaitConditionHandle
Properties:
ExampleWaitCondition:
Type: AWS::CloudFormation::WaitCondition
DependsOn: ExampleEC2Instance
Properties:
Handle:
Ref: ExampleWaitHandle
Timeout: 600