This repository contains a solution that demonstrates how to use the Diagrid Catalyst serverless Dapr APIs for workflow, service invocation, pub/sub, and state management to build a distributed pizza ordering system.
đź“– Read the blog post for more context.
The solution includes:
- Vercel; to host the website (based on Vue) and two serverless functions (JavaScript).
- Two Dapr web services written in .NET, PizzaOrderService and KitchenService.
- Ably; to provide realtime communication between the PizzaOrderService and the website.
- A key/value store to manage inventory (managed by Diagrid).
- A pub/sub message broker to communicate between the PizzaOrderService and the KitchenService (managed by Diagrid).
- Diagrid Catalyst that offers serverless APIs for communication, state, and workflow powered by Dapr.
The PizzaOrderService contains a Dapr workflow that orchestrates the activities for checking the inventory and communicating with the KitchenService.
The workflow also contains activities for sending realtime messages to the website, these have been omitted from the workflow diagram to keep it concise.
The following services, tools, and frameworks are required for this demo:
- Diagrid Catalyst account (sign up for private beta access) and the Diagrid CLI
- Vercel account (hobby) and the Vercel CLI
- Ably account (free)
- .NET 8 SDK
- Node 18
All the code for the website, serverless functions and back-end services is available in this catalyst-pizza-demo GitHub repository. The repository also contains a devcontainer configuration that has the following preinstalled: .NET 8, Node LTS, Vercel CLI, Diagrid CLI.
You can use this devcontainer locally in VSCode (requires Docker Desktop) or directly in GitHub Codespaces. The
npm install
anddotnet build
commands described in this README can be skipped if the devcontainer is used.
- Fork this repo and clone it locally or use GitHub Codespaces.
Ably is used as the serverless realtime messaging component. There is a default Ably app when you sign up for an account that can be used for this demo. Alternatively, you can create a new Ably app.
- Log into the Ably portal.
- Using the Ably portal: copy the Root API key from the Ably app. This will be copied later as an environment variable for both Vercel and Diagrid.
The Vue-based front-end and two JavaScript functions are hosted on Vercel. The Vercel CLI is used to configure and run these resources locally.
-
Open a terminal in the root of the repository login with the Vercel CLI:
vercel login
-
Go to the
front-end
folder and run:npm install
-
Go back to the root of the repository and setup the Vercel project by running:
vercel
Follow the CLI prompts, and select the following options:
- Setup and deploy:
Y
- Scope:
<your account name>
- Link to existing project:
N
- What's your project's name?
catalyst-pizza-project
- In which directory is your code located?
./front-end
- Want to modify these settings? [y/N]
n
- Wait for the deployment to complete.
- Setup and deploy:
-
An environment variable is used in the getAblyToken function to generate a token for the website to communicate with the Ably realtime service. Add the Ably API token variable by running
vercel env add
:- Variable name:
ABLY_API_KEY
- Variable value: Use the Ably API key obtained from the Ably portal earlier
- Select
Development
as the environment.
- Variable name:
-
Another environment variable is used in the placeOrder function to send a request to the PizzaOrderService that will start the workflow. Add the WORKFLOW_URL variable by running
vercel env add
:- Variable name:
WORKFLOW_URL
- Variable value:
http://localhost:5064/workflow/orderReceived
- Select
Development
as the environment.
- Variable name:
-
Run
vercel pull
to pull the configuration from Vercel to your local environment. -
Run
vercel build
to build the website and the serverless functions.
Diagrid Catalyst provides serverless Dapr APIs that enables developers to quickly build distributed applications with workflow, pub/sub messaging, service invocation, and state management capabilities. Diagrid also provides managed infrastructure for storing data in a key/value store, pub/sub messaging, and workflow, which are all used in this solution.
The Diagrid CLI is used to configure the resources and run the .NET services locally.
-
Open another terminal in the root of the repository and use the Diagrid CLI to login to Diagrid:
diagrid login
-
Create a new Catalyst project named
catalyst-pizza-project
and use the Diagrid managed pub/sub broker & KV store, and enable the managed workflow API:diagrid project create catalyst-pizza-project --deploy-managed-pubsub --deploy-managed-kv --enable-managed-workflow --wait
-
To set this project as the default in the CLI run:
diagrid project use catalyst-pizza-project
-
Create a new App ID for the PizzaOrderService:
diagrid appid create pizzaorderservice
-
Create a new App ID for the KitchenService:
diagrid appid create kitchenservice
-
Before continuing, check the App IDs to make sure they have been created:
diagrid appid list
-
Create a pub/sub subscription for the KitchenService to receive messages from the PizzaOrderService:
diagrid subscription create pizzaorderssub --connection pubsub --topic pizza-orders --route /prepare --scopes kitchenservice
-
Create a pub/sub subscription for the PizzaOrderService to receive messages from the KitchenService:
diagrid subscription create preparedorderssub --connection pubsub --topic prepared-orders --route /workflow/orderPrepared --scopes pizzaorderservice
-
Verify that creation of the subscriptions is completed:
diagrid subscription list
-
Run
diagrid dev scaffold
to create a new local dev environment file . This creates a yaml file, named dev-<PROJECT NAME>.yaml with the following content:project: catalyst-pizza-project apps: - appId: kitchenservice appPort: 0 env: DAPR_API_TOKEN: diagrid://<dapr_api_token> DAPR_APP_ID: kitchenservice DAPR_GRPC_ENDPOINT: https://<grpc_endpoint> DAPR_HTTP_ENDPOINT: https://<http_endpoint> workDir: kitchenservice command: [] - appId: pizzaorderservice appPort: 0 env: DAPR_API_TOKEN: diagrid://<dapr_api_token> DAPR_APP_ID: pizzaorderservice DAPR_GRPC_ENDPOINT: https://<grpc_endpoint> DAPR_HTTP_ENDPOINT: https://<http_endpoint> workDir: pizzaorderservice command: [] appLogDestination: ""
-
Update the
appPort
for the kitchenservice to5066
-
Update the
appPort
for the pizzaorderservice to5064
. -
Update the
command
arguments to["dotnet", "run"]
for both apps. -
Update the
workDir
argument to point toback-end/KitchenService
andback-end/PizzaOrderService
respectively. -
Update the
appLogDestination
toconsole
. -
Add an
ABLY_API_KEY
environment variable for the pizzaorderservice app and set the value to the Ably API key obtained from the Ably portal. -
Save the changes to the file.
Update the key/value store to allow state sharing
The two .NET services both use the same data in the key/value store to manage inventory and orders. Since this is not the default usage of state stores and services when using Dapr, an attribute needs to be set to enable this. The default behavior is that a key is prefixed with the app ID of the service that is using it. In this case, however, the keyPrefix
is set to name
to make sure both services use the same keys.
-
Run the following command to update the managed key/value store:
diagrid connection apply -f ./infra/kv.yml
This will upload the
kv.yml
file to Diagrid and update the configuration of the kvstore connection sokeyPrefix
is set toname
.
The two .NET services use the Dapr .NET client SDK for workflow, and pub/sub messaging. The DaprClient
is configured to use the endpoints provided by Diagrid Catalyst in the Program.cs file:
var apiToken = Environment.GetEnvironmentVariable("DAPR_API_TOKEN");
var grpcEndpoint = Environment.GetEnvironmentVariable("DAPR_GRPC_ENDPOINT");
var httpEndpoint = Environment.GetEnvironmentVariable("DAPR_HTTP_ENDPOINT");
builder.Services.AddDaprClient(options => {
options.UseDaprApiToken(apiToken);
options.UseGrpcEndpoint(grpcEndpoint);
options.UseHttpEndpoint(httpEndpoint);
});
To use service invocation with the HTTP API, the HttpClient
is configured with the DAPR_APP_ID
and DAPR_API_TOKEN
environment variables:
var appId = Environment.GetEnvironmentVariable("DAPR_APP_ID");
var apiToken = Environment.GetEnvironmentVariable("DAPR_API_TOKEN");
builder.Services.AddHttpClient(
"daprEndpoint",
client => {
client.BaseAddress = new Uri(httpEndpoint);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("dapr-app-id", appId);
client.DefaultRequestHeaders.Add("dapr-api-token", apiToken);
});
-
Open a terminal in the root of the repository.
-
To restore and build the .NET projects run:
dotnet build ./back-end/PizzaOrderService dotnet build ./back-end/KitchenService
-
Run
diagrid dev start
to start thePizzaOrderService
and theKitchenService
. -
Using another terminal in the root of the repository run
vercel dev
to start the website and the serverless functions locally. -
Navigate to the URL provided by the Vercel CLI to view the website.
-
Select some pizzas, place an order, and watch the progress of the workflow in realtime.
You can use the API explorer in the Catalyst web UI to interact with the managed Dapr APIs. If you want to retrieve the order item from the key./value store that has just been processed follow these steps:
-
Open the browser devtools console of the browser that is running the demo (a pizza order must be started or completed).
-
The order is logged to the console as a JSON object. Copy the
OrderId
property value. -
Navigate to the Catalyst web UI. Ensure you're in the
catalyst-pizza-project
project. -
Select App IDs in and click on the API explorer tab.
- Select the
State API
. - Select the
pizzaorderservice
as the app ID. - Select
GET
as the API operation. - Select
kvstore
as the state connection. - Enter
Order-<ORDER-ID>
as the key, where<ORDER-ID>
is substituted with the value copied from the devtools console.
- Select the
-
Click Send. The response should contain the state of the order item with
"status": "CompletedPreparation"
.
Congratulations! You’ve now used the Diagrid Catalyst serverless Dapr APIs for workflow, pub/sub messaging, service invocation, and state management. The ability to use these APIs from anywhere, without the overhead of managing Kubernetes clusters, brings great flexibility to developers on any platform to build distributed applications. The Dapr applications used in this demo can be hosted on any cloud. The demo uses the Diagrid managed infrastructure for key/value storage and pub/sub messaging, but these can be swapped out for other cloud-based resources, similarly to switching open-source Dapr components. You can extend this demo with an alternative pub/sub broker or state store by configuring other infrastructure connections.
Any questions or comments about this demo? Join the Diagrid Community on Discourse and post a message in the Catalyst category. Have you made something with Catalyst? Post a message in the Built with Catalyst category, we love to see your creations!