See HOWTORUN.md for details on environment and dependencies setup.
This demo is a simple application an Infrastructure/Platform team might host to simplify application team requests for Cloud Resources. It shows how a team might use Temporal to orchestrate Cloud Resource provisioning by delegating to an Infrastructure-As-Code (IaC) tool like Pulumi.
It is common for Infrastructure teams to use an IaC tool to manage Cloud Resources because of their great state management and dependency resolution features.
Automating failure handling during these updates or orchestrating units of these resources for application team support quickly reveals the need for an orchestrator that can ensure your infrastructure remains in a consistent state.
This demo presumes local ability to create and manage AWS Resources. Also, it writes changes to the Pulumi stack configuration in-place. Neither of these are admittedly "production grade" approaches.
Prerequisites | __ | Features | __ | Patterns | |||
---|---|---|---|---|---|---|---|
Network Connection | ✅ | __ | Schedule | __ | Entity | ||
Golang 1.18+ | ✅ | __ | Local Activity | __ | Long-Running | ✅ | |
NodeJS & NPM | ✅ | __ | Timer | ✅ | __ | Fanout | |
Temporal CLI | ✅ | __ | Signal | ✅ | __ | Continue As New | |
Pulumi | ✅ | __ | Query | ✅ | __ | Manual Intervention | ✅ |
AWS Account | ✅ | __ | Update | __ | Saga | ||
✅ | __ | Heartbeat | ✅ | __ | Long-polling | ||
__ | Retry | ✅ | __ | ||||
__ | Data Converter | __ | |||||
__ | Polyglot | ✅ | __ |
Polyglot Pragmatism
This project was started as a Golang project but the most relevant Pulumi sample used TypeScript.
Targetting a specific TaskQueue
from the Golang Orchestration that maps to a hosted TypeScript application kept
development humming along without a hitch. No porting or rewrites needed.
Resuming Progress Made Simple
Resuming a use case in response to a Human interaction is non-trivial to build without Temporal. Using Temporal, it's merely a matter of wiring a Signal execution to a known Workflow. Temporal takes care of reloading current state and finding the Workflow without worrying about "which server" is handling the request.
Heartbeats
Cloud Resources can take a long time to provision. The built-in support for Heartbeats in long-running activities is simply a configuration parameter to control the rescheduling of Activity executions.
Guaranteed Time Limits
The use of AwaitWithTimeout
makes it simple to wait for Human interaction while applying a time limit
on their response. There is no more need to continually query persistence for these kinds of
time limits to invalidate requests correctly.
Show Me Why It Broke
Failures encountered in Long-running Activities in any system are hard to diagnose due to
log overload. Temporal UI Pending Activities
view makes it clear whether there is
some connectivity issue or some conflict with refreshing Pulumi state to know where to fix the
real problem.
Four distinct applications come together to meet this use case.
/internal
: (Golang) contains implementation of the Domain, leveraging Temporal Workflow Orchestration to express the use cases./provisioning_aws
: (TypeScript) contains the AWS-specific activities for provisioning Cloud Resources./bff
: (Golang) contains the backend API server to support the Single-Page Application (SPA). NOTE that theTemporal SDK Client
is used here to Start Workflows./ui
: (TypeScript) contains the Svelte SPA application teams and infra teams use
See the Makefile for specific commands to run these applications.
The implementation here only supports AWS but supporting other cloud providers becomes quickly obvious by targeting Temporal Task Queues.
First, the team enters basic information about their application, team, and who they would like to authorize
the request for provisioning
resources.
The demo then shows what the Authorizer
they specified will see.
The Authorizer
specifies the AWS Region and AWS Profile to use for completing the provisioning request (if approving).
The Authorizer
selects to Approve or Reject this request.
An appropriate response page is shown based on their selection.
When the user Submit
s the request, a Temporal Workflow is started, performing some
initial steps like verifying team identity and other pre-flight checks. The Orchestration
is then suspended to await the Authorizer
"Approved" or "Rejected" decision.
By default, the request will wait for 2 minutes to receive an authorization before canceling the request.
The Golang "domain" code for the Orchestration is found in the
/internal/orchestrations
directory.
When the Authorizer
has approved this request, the ProvisionApplication Orchestration
receives this Temporal Signal to allow the suspended Workflow to make progress. This Signal includes
the Authorizer's assignment of AWS region
and which Profile
to use to execute the Pulumi update.
For simplicity, we opted to merely adapt the Pulumi sample found here to programmatically use Pulumi to deploy an S3 Bucket to AWS.
You might notice this sample is written in TypeScript but our primary Orchestration logic is written in Golang.
Enter Temporal's simple, powerful way to support polyglot applications.
Many organizations must unify disparate languages. Temporal solves this
by making it simple to target specific hosts for Activity executions using
the TaskQueue
activity option. Teams can choose the Right Tool for the Job while retaining the composition
every architecture strives for. Temporal supports six languages.
In this demo, we create an "Activity Worker" that hosts the Pulumi automation to be invoked as an Activity by the main Orchestration.
The TypeScript Pulumi application is found in the
/provisioning_aws
directory.