diff --git a/docs/tutorials/go/background-check/index.mdx b/docs/tutorials/go/background-check/index.mdx
index 9f2d6dcc..287434f3 100644
--- a/docs/tutorials/go/background-check/index.mdx
+++ b/docs/tutorials/go/background-check/index.mdx
@@ -1,11 +1,9 @@
---
id: index
-title: Build a Background Check application with Temporal and Go
+title: Build a Background Check application with Go
description: Learn Temporal and its features while building a Background Check application
-sidebar_label: Build a Background Check application with Temporal and Go
tags:
-- long-running
-- human-in-the-loop
+- Go
keywords:
- long-running
- human in the loop
diff --git a/docs/tutorials/go/ecommerce/index.md b/docs/tutorials/go/build-an-ecommerce-app/index.md
similarity index 92%
rename from docs/tutorials/go/ecommerce/index.md
rename to docs/tutorials/go/build-an-ecommerce-app/index.md
index 3344c36d..683506d9 100644
--- a/docs/tutorials/go/ecommerce/index.md
+++ b/docs/tutorials/go/build-an-ecommerce-app/index.md
@@ -1,11 +1,14 @@
---
-title: "Build an eCommerce App With Temporal and Go"
+id: build-ecommerce-app
+title: "Build an eCommerce App With Go"
sidebar_position: 1
-keywords: [Go,tutorial,temporal,workflows, sending email,testing]
description: "Four-part tutorial series on building an eCommerce application with Temporal and Go."
+keywords: [Go,tutorial,temporal,workflows, sending email,testing]
+tags:
+- Go
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2021-09-14
-image: /img/temporal-logo-twitter-card.png
---
![Temporal Go SDK](/img/sdk_banners/banner_go.png)
diff --git a/docs/tutorials/go/ecommerce/part1.md b/docs/tutorials/go/build-an-ecommerce-app/part1.md
similarity index 100%
rename from docs/tutorials/go/ecommerce/part1.md
rename to docs/tutorials/go/build-an-ecommerce-app/part1.md
index 9ae1f207..fc212381 100644
--- a/docs/tutorials/go/ecommerce/part1.md
+++ b/docs/tutorials/go/build-an-ecommerce-app/part1.md
@@ -6,10 +6,10 @@ tags:
- tutorial
keywords: [go, golang, temporal, sdk, tutorial, workflows, ecommerce]
slug: build-an-ecommerce-app-with-temporal-part-1
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2021-05-18
author: Valeri Karpov
-image: /img/temporal-logo-twitter-card.png
---
![Temporal Go SDK](/img/sdk_banners/banner_go.png)
diff --git a/docs/tutorials/go/ecommerce/part2.md b/docs/tutorials/go/build-an-ecommerce-app/part2.md
similarity index 100%
rename from docs/tutorials/go/ecommerce/part2.md
rename to docs/tutorials/go/build-an-ecommerce-app/part2.md
diff --git a/docs/tutorials/go/ecommerce/part3.md b/docs/tutorials/go/build-an-ecommerce-app/part3.md
similarity index 100%
rename from docs/tutorials/go/ecommerce/part3.md
rename to docs/tutorials/go/build-an-ecommerce-app/part3.md
diff --git a/docs/tutorials/go/ecommerce/part4.md b/docs/tutorials/go/build-an-ecommerce-app/part4.md
similarity index 100%
rename from docs/tutorials/go/ecommerce/part4.md
rename to docs/tutorials/go/build-an-ecommerce-app/part4.md
diff --git a/docs/tutorials/go/subscriptions/index.md b/docs/tutorials/go/build-an-email-drip-campaign/index.md
similarity index 98%
rename from docs/tutorials/go/subscriptions/index.md
rename to docs/tutorials/go/build-an-email-drip-campaign/index.md
index 3817857d..1225e1eb 100644
--- a/docs/tutorials/go/subscriptions/index.md
+++ b/docs/tutorials/go/build-an-email-drip-campaign/index.md
@@ -1,11 +1,14 @@
---
-title: Build an email subscription workflow with Temporal and Go
+id: build-an-email-drip-campaign-go
+title: Build an email drip campaign with Go
sidebar_position: 3
-keywords: [Go,tutorial,temporal,workflows,SDK,subscription]
description: Implement an email subscription application in Go with Temporal's Workflows, Activities, and Queries, using the Temporal Client in a web API.
+keywords: [Go,tutorial,temporal,workflows,SDK,subscription]
+tags:
+- Go
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2023-09-28
-image: /img/temporal-logo-twitter-card.png
---
### Introduction
@@ -18,7 +21,7 @@ By the end of this tutorial, you'll have a clear understanding of how to use Tem
You'll find the code for this tutorial on GitHub in the [email-subscription-project-go](https://github.com/temporalio/email-subscription-project-go) repository.
-## Prerequisites
+## Prerequisites
- [Set up a local development environment for Temporal and Go](https://learn.temporal.io/getting_started/go/dev_environment/).
- Complete the [Hello World](https://learn.temporal.io/getting_started/go/hello_world_in_go/) to ensure you understand the basics of creating Workflows and Activities with Temporal.
@@ -151,7 +154,7 @@ The `SubscriptionWorkflow()` function uses a `for` loop to send the emails. The
Later in this tutorial, you will find that the user's email address is set to the [Workflow Id](https://docs.temporal.io/workflows#workflow-id). This means that attempting to subscribe with the same email address twice will result in an error and prevent the Workflow Execution from spawning again.
-Therefore, only one running Workflow Execution per email address can exist within the associated [Namespace](https://docs.temporal.io/namespaces).
+Therefore, only one running Workflow Execution per email address can exist within the associated [Namespace](https://docs.temporal.io/namespaces).
This ensures that the user won't receive multiple email subscriptions. This also helps reduce the complexity of the code you have to write and maintain.
With this Workflow Definition in place, you can now develop an Activity to send emails.
@@ -236,7 +239,7 @@ Now that you've written the logic to execute the Workflow and Activity Definitio
## Build the web server
The web server is used to handle requests.
-This tutorial uses [Go's HTTP library](https://pkg.go.dev/net/http) as the entry point for initiating Workflow Executions and for communicating with the `/subscribe`, `/unsubscribe`, and `/details` endpoints.
+This tutorial uses [Go's HTTP library](https://pkg.go.dev/net/http) as the entry point for initiating Workflow Executions and for communicating with the `/subscribe`, `/unsubscribe`, and `/details` endpoints.
Create a `gateway` folder with the file `main.go`.
Establish your JSON request and response structs, set the endpoint handlers, and connect to the Temporal Client.
@@ -388,10 +391,10 @@ After decoding the request, use `workflowOptions` to pass in the user's email ad
This ensures that the email is unique across all Workflows so that the user can't sign up multiple times.
They'll only receive the emails they've subscribed to, and once they unsubscribe, they cancel the Workflow run.
-With this endpoint in place, you can now send a "POST" request to `/subscribe` with an email address in the request body.
+With this endpoint in place, you can now send a "POST" request to `/subscribe` with an email address in the request body.
In return, you'll receive a JSON response that shows a new Workflow has started, along with a welcome email.
-But how would you get details about the subscription?
+But how would you get details about the subscription?
In the next section, you'll query your Workflow to get back information on the state of things.
## Add a Query
@@ -423,7 +426,7 @@ This Query handler returns the contents of the `emailDetails` variable. Queries
You can use Queries even if the Workflow completes, which is useful for when the user unsubscribes but still wants to retrieve information about their subscription.
-Now that you've added the ability to Query your Workflow, add the ability to Query from the web API.
+Now that you've added the ability to Query your Workflow, add the ability to Query from the web API.
Create a function called `showDetailsHandler()` in which a user can get information about their subscription details.
Make sure to include error handlers to ensure proper "GET" requests and responses.
@@ -584,12 +587,12 @@ func unsubscribeHandler(w http.ResponseWriter, r *http.Request) {
```
-The `CancelWorkflow()` function sends a cancellation request to the Workflow Execution you started on the `/subscribe` endpoint.
+The `CancelWorkflow()` function sends a cancellation request to the Workflow Execution you started on the `/subscribe` endpoint.
When the Workflow receives the cancellation request, it will cancel the Workflow Execution and return a `CancelledError` to the Workflow Execution.
This is then handled by the error handlers included in the `unsubscribeHandler()` function.
-Users can now send a "DELETE" request to `/unsubscribe` to cancel the Workflow associated with the request body's email address.
+Users can now send a "DELETE" request to `/unsubscribe` to cancel the Workflow associated with the request body's email address.
This lets users unsubscribe from the email list and prevent any further emails from sending.
Now that you've added the ability to unsubscribe from the email list, test your application code to ensure it works as expected.
@@ -670,9 +673,9 @@ ok subscribeemails 0.285s
```
With a cancellation request that fires after five seconds, this test shows the successful creation of a subscription as well as its cancellation.
-You've successfully written, executed, and passed a Cancellation Workflow test.
+You've successfully written, executed, and passed a Cancellation Workflow test.
-Temporal's Go SDK provides a number of functions that help you test your Workflow Executions.
+Temporal's Go SDK provides a number of functions that help you test your Workflow Executions.
By following the best practices for testing your code, you can be confident that your Workflows are reliable and performant.
## Conclusion
diff --git a/docs/tutorials/java/background-check/index.mdx b/docs/tutorials/java/background-check/index.mdx
index 621fc978..f0c29483 100644
--- a/docs/tutorials/java/background-check/index.mdx
+++ b/docs/tutorials/java/background-check/index.mdx
@@ -1,12 +1,9 @@
---
id: index
-title: Temporal Java SDK Background Check tutorial
+title: Build a Background Check application with Java
description: Learn Temporal and its features while building a Background Check application
-sidebar_label: Build a Background Check application with Temporal and Java
tags:
- java
-- long-running
-- human-in-the-loop
keywords:
- java
- long-running
diff --git a/docs/tutorials/java/build-an-email-drip-campaign/index.md b/docs/tutorials/java/build-an-email-drip-campaign/index.md
index 76d08f8f..ffabfd46 100644
--- a/docs/tutorials/java/build-an-email-drip-campaign/index.md
+++ b/docs/tutorials/java/build-an-email-drip-campaign/index.md
@@ -23,7 +23,7 @@ This reduces the complexity of the code you have to write and support.
You'll create an endpoint for users to give their email address, and then create a new Workflow execution using that email address which will simulate sending an email message at certain intervals.
The user can check on the status of their subscription, which you'll handle using a Query, and they can end the subscription at any time by unsubscribing, which you'll handle by cancelling the Workflow Execution.
-You can view the user's entire process through Temporal's Web UI.
+You can view the user's entire process through Temporal's Web UI.
For this tutorial, you'll simulate sending emails, but you can adapt this example to call a live email service in the future.
By the end of this tutorial, you'll have a clear understand how to use Temporal to create and manage long-running Workflows within a web application.
@@ -71,7 +71,7 @@ Before writing the Workflow Definition, you'll define the data objects used by t
You'll also define the Task Queue name you'll use in your Worker.
Create the package directories for this project:
-
+
```
src
├── main
@@ -327,7 +327,7 @@ The `run` method executes the `sendEmail()` Activity with the following paramete
A `start_to_close_timeout` parameter tells the Temporal Server to time out the Activity 10 seconds from when the Activity starts.
-The loop also includes a `Workflow.sleep()` statement that causes the Workflow to pause for a set amount of time between emails.
+The loop also includes a `Workflow.sleep()` statement that causes the Workflow to pause for a set amount of time between emails.
You can define this in seconds, days, months, or even years, depending on your business logic.
If there's a cancellation request, the request throws a `CanceledFailure` error, which you can catch and respond.
@@ -491,7 +491,7 @@ In the `Controller.java` file, define a `/subscribe` endpoint so that users can
In the `startSubscription()` method, use the `WorkflowClient` instance to start your Workflow Execution.
-The `WorkflowData` object is used to pass the email address given by the user to the Workflow Execution and sets the Workflow Id.
+The `WorkflowData` object is used to pass the email address given by the user to the Workflow Execution and sets the Workflow Id.
This ensures that the email is unique across all Workflows so that the user can't sign up multiple times, only receive the emails they've subscribed to, and when they cancel; they cancel the Workflow run.
With this endpoint in place, you can now send a POST request to `/subscribe` with an email address in the request body to start a new Workflow that sends an email to that address.
@@ -600,7 +600,7 @@ Here's the relevant section as a reminder:
With this endpoint in place, users can send a `DELETE` request to `unsubscribe` with an email address in the request body to cancel the Workflow associated with that email address.
This allows users to unsubscribe from the email list and prevent any further emails from sending.
-Now that you've added the ability to unsubscribe from the email list, build your server app.
+Now that you've added the ability to unsubscribe from the email list, build your server app.
## Build the server app
diff --git a/docs/tutorials/php/subscriptions/index.md b/docs/tutorials/php/build-a-recurring-billing-app/index.md
similarity index 98%
rename from docs/tutorials/php/subscriptions/index.md
rename to docs/tutorials/php/build-a-recurring-billing-app/index.md
index fd0e5de6..fb3f79ba 100644
--- a/docs/tutorials/php/subscriptions/index.md
+++ b/docs/tutorials/php/build-a-recurring-billing-app/index.md
@@ -1,13 +1,14 @@
---
-id: subscription-tutorial
+id: build-a-recurring-billing-app-php
+title: Build a recurring billing subscription system with PHP
sidebar_position: 1
+description: In this tutorial you'll build a realistic monthly subscription payments workflow that can be canceled while it runs.
keywords: [PHP, temporal, sdk, tutorial, subscriptions, signals]
-tags: [PHP, SDK]
+tags:
+- PHP
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2021-10-01
-title: Subscription walkthrough with Temporal in PHP
-description: In this tutorial you'll build a realistic monthly subscription payments workflow that can be canceled while it runs.
-image: /img/temporal-logo-twitter-card.png
---
![Temporal PHP SDK](/img/sdk_banners/banner_php.png)
@@ -34,7 +35,7 @@ Of course, this all has to be fault-tolerant, scalable to millions of customers,
## Prerequisites
- [Set up a local development environment for developing Temporal applications using PHP](/getting_started/php/dev_environment/index.md)
-- Review the [Hello World in PHP tutorial](/getting_started/php/hello_world_in_php/index.md) and understood the basics of getting a Temporal PHP SDK project up and running.
+- Review the [Hello World in PHP tutorial](/getting_started/php/hello_world_in_php/index.md) and understood the basics of getting a Temporal PHP SDK project up and running.
## Create the Workflow
diff --git a/docs/tutorials/php/booking_saga/images/booking-saga-flow.png b/docs/tutorials/php/build_a_trip_booking_app/images/booking-saga-flow.png
similarity index 100%
rename from docs/tutorials/php/booking_saga/images/booking-saga-flow.png
rename to docs/tutorials/php/build_a_trip_booking_app/images/booking-saga-flow.png
diff --git a/docs/tutorials/php/booking_saga/index.md b/docs/tutorials/php/build_a_trip_booking_app/index.md
similarity index 98%
rename from docs/tutorials/php/booking_saga/index.md
rename to docs/tutorials/php/build_a_trip_booking_app/index.md
index 09d73fef..beea83f8 100644
--- a/docs/tutorials/php/booking_saga/index.md
+++ b/docs/tutorials/php/build_a_trip_booking_app/index.md
@@ -1,13 +1,15 @@
---
-id: booking-saga-tutorial
+id: build_a_trip_booking_app-php
+title: Build a trip booking system with PHP
sidebar_position: 1
+description: In this tutorial, you'll explore the different components that make up the Temporal Booking Saga code sample.
keywords: [PHP, temporal, sdk, tutorial, saga pattern, transactions, compensations]
-tags: [PHP, SDK, Saga]
+tags:
+- php
+- saga
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2021-10-01
-title: Create a trip booking system with the Saga pattern and Temporal in PHP
-description: In this tutorial, you'll explore the different components that make up the Temporal Booking Saga code sample.
-image: /img/temporal-logo-twitter-card.png
---
![Temporal PHP SDK](/img/sdk_banners/banner_php.png)
@@ -31,7 +33,7 @@ All of these steps together make up a **distributed transaction** that crosses
## Prerequisites
- [Set up a local development environment for developing Temporal applications using PHP](/getting_started/php/dev_environment/index.md)
-- Review the [Hello World in PHP tutorial](/getting_started/php/hello_world_in_php/index.md) to understood the basics of getting a Temporal PHP SDK project up and running.
+- Review the [Hello World in PHP tutorial](/getting_started/php/hello_world_in_php/index.md) to understood the basics of getting a Temporal PHP SDK project up and running.
## Review the Saga architecture pattern
diff --git a/docs/tutorials/python/background-check/index.mdx b/docs/tutorials/python/background-check/index.mdx
index 6f1dafda..e954d186 100644
--- a/docs/tutorials/python/background-check/index.mdx
+++ b/docs/tutorials/python/background-check/index.mdx
@@ -1,12 +1,10 @@
---
id: index
title: Temporal Python SDK Background Check tutorial
-description: Learn Temporal and its features while building a Background Check application
sidebar_label: Build a Background Check application with Temporal and Python
+description: Learn Temporal and its features while building a Background Check application
tags:
- python
-- long-running
-- human-in-the-loop
keywords:
- python
- long-running
diff --git a/docs/tutorials/python/background-check/introduction.mdx b/docs/tutorials/python/background-check/introduction.mdx
index 6c6d59c5..e2008f0d 100644
--- a/docs/tutorials/python/background-check/introduction.mdx
+++ b/docs/tutorials/python/background-check/introduction.mdx
@@ -112,7 +112,7 @@ Additional Python code samples are in the [temporalio/samples-python](https://gi
- [Temporal 101 with Python](https://learn.temporal.io/courses/temporal_101/python)
- [Python tutorials](https://learn.temporal.io/tutorials/python/)
- [Build a data pipeline Workflow with Temporal and Python](https://learn.temporal.io/tutorials/python/data-pipelines/)
- - [Build a subscription workflow with Temporal and Python](https://learn.temporal.io/tutorials/python/subscriptions/)
+ - [Build an Email drip campaign with Python](https://learn.temporal.io/tutorials/python/build-an-email-drip-campaign/)
- Blog posts
- [Temporal 101: Learn Temporal with Python](https://temporal.io/blog/temporal-101-learn-temporal-with-python)
- [Temporal Python 1.0.0 – A Durable, Distributed Asyncio Event Loop](https://temporal.io/blog/durable-distributed-asyncio-event-loop)
diff --git a/docs/tutorials/python/data-pipelines/index.md b/docs/tutorials/python/build-a-data-pipeline/index.md
similarity index 99%
rename from docs/tutorials/python/data-pipelines/index.md
rename to docs/tutorials/python/build-a-data-pipeline/index.md
index ee375d48..7b4fab50 100644
--- a/docs/tutorials/python/data-pipelines/index.md
+++ b/docs/tutorials/python/build-a-data-pipeline/index.md
@@ -1,13 +1,14 @@
---
-id: data-pipeline-tutorial
+id: build-a-data-pipeline-python
+title: Build a data pipeline with Python
sidebar_position: 3
+description: You'll implement a data pipeline application in Python, using Temporal's Workflows, Activities, and Schedules to orchestrate and run the steps in your pipeline.
keywords: [Python, temporal, sdk, tutorial]
-tags: [Python, SDK]
+tags:
+- Python
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2023-05-01
-title: Build a data pipeline Workflow with Temporal and Python
-description: You'll implement a data pipeline application in Python, using Temporal's Workflows, Activities, and Schedules to orchestrate and run the steps in your pipeline.
-image: /img/temporal-logo-twitter-card.png
---
![Temporal Python SDK](/img/sdk_banners/banner_python.png)
@@ -283,7 +284,7 @@ For this example, `stories` is processed by a [Pandas Data Frame](https://pandas
The code runs in an `asyncio` event loop.
-To run your code, open two terminal windows.
+To run your code, open two terminal windows.
In the first terminal, run this command to start the worker:
@@ -330,7 +331,7 @@ You've successfully run your Workflow and explored the Event History, now schedu
You just built and ran a Workflow, that returns information from your data pipeline. Now, you'll run this Workflow on a schedule.
Cron jobs have a reputation for fragility because they run commands in a different environment than the user's shell, which can lead to configuration management issues and random machine failures.
-Additionally, cron errors are not always directed to live email, making it hard to know when things go wrong.
+Additionally, cron errors are not always directed to live email, making it hard to know when things go wrong.
While newer systems like systemd timers and Kubernetes cron jobs fix some of these issues, there is still a reliance on the archaic five-field string syntax for specifying times.
Fortunately, Temporal provides an alternative solution for scheduling workflows that doesn't require configuring additional dependencies or worrying about system alerts.
diff --git a/docs/tutorials/python/subscriptions/index.md b/docs/tutorials/python/build-an-email-drip-campaign/index.md
similarity index 99%
rename from docs/tutorials/python/subscriptions/index.md
rename to docs/tutorials/python/build-an-email-drip-campaign/index.md
index a2dbf9bb..084874e0 100644
--- a/docs/tutorials/python/subscriptions/index.md
+++ b/docs/tutorials/python/build-an-email-drip-campaign/index.md
@@ -1,11 +1,13 @@
---
-id: subscription-tutorial
+id: build-an-email-drip-campaign-python
+title: Build an email drip campaign with Python
sidebar_position: 3
keywords: [Python, temporal, sdk, tutorial, entity workflow, email subscription, sending emails]
-tags: [Python, SDK]
+tags:
+- Python
+- entity workflow
last_update:
date: 2024-03-06
-title: Build an email subscription Workflow with Temporal and Python
description: Implement an email subscription application with Temporal's Workflows, Activities, and Queries, and allow users to start your business logic through a web action.
image: /img/temporal-logo-twitter-card.png
---
diff --git a/docs/tutorials/typescript/background-check/index.mdx b/docs/tutorials/typescript/background-check/index.mdx
index fe440269..21a4baa7 100644
--- a/docs/tutorials/typescript/background-check/index.mdx
+++ b/docs/tutorials/typescript/background-check/index.mdx
@@ -1,12 +1,9 @@
---
id: index
-title: Temporal TypeScript SDK Background Check tutorial
+title: Build a Background Check application with TypeScript
description: Learn Temporal and its features while building a Background Check application
-sidebar_label: Build a Background Check application with Temporal and TypeScript
tags:
- typescript
-- long-running
-- human-in-the-loop
keywords:
- typescript
- long-running
@@ -22,7 +19,6 @@ In this tutorial, you will build a Background Check application using the Tempor
The tutorial is laid out in the following chapters:
-
- [Introduction](/tutorials/typescript/background-check/introduction.mdx)
- [Project setup](/tutorials/typescript/background-check/project-setup.mdx)
- [Develop for durability](/tutorials/typescript/background-check/durable-execution.mdx)
diff --git a/docs/tutorials/typescript/background-check/introduction.mdx b/docs/tutorials/typescript/background-check/introduction.mdx
index f563f0d6..f5bf1f24 100644
--- a/docs/tutorials/typescript/background-check/introduction.mdx
+++ b/docs/tutorials/typescript/background-check/introduction.mdx
@@ -76,7 +76,7 @@ Further resources for learning how to use the SDK include the following:
- [Building Reliable Distributed Systems in Node.js](https://temporal.io/blog/building-reliable-distributed-systems-in-node): An introduction to Temporal and its value through a sample web app, [temporal.menu](https://temporal.menu/).
- The [TypeScript SDK](https://www.youtube.com/playlist?list=PLl9kRkvFJrlTavecydpk9r6cF7qBmQJvb) YouTube playlist.
- Tutorials
- - [Build a recurring billing subscription system with TypeScript](https://learn.temporal.io/tutorials/typescript/subscriptions/)
+ - [Build a recurring billing subscription system with TypeScript](https://learn.temporal.io/tutorials/typescript/recurring-billing-system/)
- [Choose Your Own Adventure Bot walkthrough in TypeScript](https://learn.temporal.io/tutorials/typescript/chatbot/)
- Blog posts
- [How Durable Execution Works](https://temporal.io/blog/building-reliable-distributed-systems-in-node-js-part-2)
diff --git a/docs/tutorials/typescript/chatbot/index.md b/docs/tutorials/typescript/build-choose-your-own-adventure-bot/index.md
similarity index 93%
rename from docs/tutorials/typescript/chatbot/index.md
rename to docs/tutorials/typescript/build-choose-your-own-adventure-bot/index.md
index 56ccedd0..975dca44 100644
--- a/docs/tutorials/typescript/chatbot/index.md
+++ b/docs/tutorials/typescript/build-choose-your-own-adventure-bot/index.md
@@ -1,13 +1,14 @@
---
-id: chatbot-tutorial
+id: build-choose-your-own-adventure-bot-ts
+title: Build a Choose Your Own Adventure Bot in TypeScript
sidebar_position: 4
+description: In this tutorial, we'll integrate all the knowledge gained from Core and Production APIs in an end-to-end, complete demo application.
+tags:
+- TypeScript
keywords: [TypeScript, temporal, sdk, tutorial]
-tags: [TypeScript, SDK]
+image: /img/temporal-logo-twitter-card.png
last_update:
date: 2021-10-01
-title: Choose Your Own Adventure Bot walkthrough in TypeScript
-description: In this tutorial, we'll integrate all the knowledge gained from Core and Production APIs in an end-to-end, complete demo application.
-image: /img/temporal-logo-twitter-card.png
---
![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)
@@ -51,15 +52,15 @@ import { ResponsivePlayer } from '@site/src/components'
-[00:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=0s) Project Intro and Demo
-[03:30](https://youtube.com/watch?v=hGIhc6m2keQ&t=210s) Temporal Worker - Activity Dependency Injection
-[07:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=420s) Temporal Sinks for Logging
-[08:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=480s) Temporal Client
-[10:50](https://youtube.com/watch?v=hGIhc6m2keQ&t=650s) RunGame Workflow and Game Logic
-[13:45](https://youtube.com/watch?v=hGIhc6m2keQ&t=825s) Async Race Design Pattern: Timers vs Humans
-[15:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=900s) Design Pattern: Polling
-[18:05](https://youtube.com/watch?v=hGIhc6m2keQ&t=1085s) Signals
-[20:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=1200s) HTTP Server for Signal
+[00:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=0s) Project Intro and Demo
+[03:30](https://youtube.com/watch?v=hGIhc6m2keQ&t=210s) Temporal Worker - Activity Dependency Injection
+[07:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=420s) Temporal Sinks for Logging
+[08:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=480s) Temporal Client
+[10:50](https://youtube.com/watch?v=hGIhc6m2keQ&t=650s) RunGame Workflow and Game Logic
+[13:45](https://youtube.com/watch?v=hGIhc6m2keQ&t=825s) Async Race Design Pattern: Timers vs Humans
+[15:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=900s) Design Pattern: Polling
+[18:05](https://youtube.com/watch?v=hGIhc6m2keQ&t=1085s) Signals
+[20:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=1200s) HTTP Server for Signal
[23:00](https://youtube.com/watch?v=hGIhc6m2keQ&t=1380s) ContinueAsNew
diff --git a/docs/tutorials/typescript/nextjs/index.md b/docs/tutorials/typescript/build-one-click-order-app-nextjs/index.md
similarity index 99%
rename from docs/tutorials/typescript/nextjs/index.md
rename to docs/tutorials/typescript/build-one-click-order-app-nextjs/index.md
index 432bf37a..7be577f0 100644
--- a/docs/tutorials/typescript/nextjs/index.md
+++ b/docs/tutorials/typescript/build-one-click-order-app-nextjs/index.md
@@ -2,14 +2,14 @@
id: build-one-click-order-app-nextjs
title: Build a one-click order application with TypeScript and Next.js
sidebar_position: 2
-keywords: [TypeScript, temporal, sdk, tutorial, NextJS]
+description: Build a One-Click Buy application with Next.js and integrate Temporal using Next.js API routes to create a durable order processing backend.
tags:
- TypeScript
+keywords: [TypeScript, temporal, sdk, tutorial, NextJS]
+image: /img/temporal-logo-twitter-card.png
+code_repo: https://github.com/temporalio/nextjs-temporal-one-click-template/
last_update:
date: 2024-06-28
-description: Build a One-Click Buy application with Next.js and integrate Temporal using Next.js API routes to create a durable order processing backend.
-image: /img/temporal-logo-twitter-card.png
-repository: https://github.com/temporalio/nextjs-temporal-one-click-template/
---
![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)
diff --git a/docs/tutorials/typescript/subscriptions/index.md b/docs/tutorials/typescript/recurring-billing-system/index.md
similarity index 95%
rename from docs/tutorials/typescript/subscriptions/index.md
rename to docs/tutorials/typescript/recurring-billing-system/index.md
index 1cba87aa..df547cd0 100644
--- a/docs/tutorials/typescript/subscriptions/index.md
+++ b/docs/tutorials/typescript/recurring-billing-system/index.md
@@ -1,11 +1,11 @@
---
-id: subscription-tutorial
+id: ts-recurring-billing-subscription-tutorial
sidebar_position: 3
keywords: [TypeScript, temporal, sdk, tutorial, entity workflow]
tags: [TypeScript, SDK]
last_update:
date: 2024-07-24
-title: Build a Recurring Billing Subscription Workflow with TypeScript
+title: Build a recurring billing subscription system with TypeScript
description: Implement a subscription application using Temporal's Workflows, Activities, Signals, and Queries, enabling the payment workflow to be canceled or modified during execution.
image: /img/temporal-logo-twitter-card.png
---
@@ -139,7 +139,7 @@ Now that you know which directory will hold your Temporal files, you can set up
}
```
-Review the scripts. By prefixing any of the scripts with `npm run`, you will be able to run your application, query for subscription details, cancel your subscription, and update your charge amount. Save your file.
+Review the scripts. By prefixing any of the scripts with `npm run`, you will be able to run your application, query for subscription details, cancel your subscription, and update your charge amount. Save your file.
Your project workspace is now configured, so you're ready to start creating your application.
@@ -199,7 +199,7 @@ You will now define the functions that handle interactions with external systems
Activities are the building blocks of a Temporal Workflow. They encapsulate the logic for tasks that interact with external services such as querying a database or calling a third-party API. One of the key benefits of using Activities is their built-in fault tolerance. If an Activity fails, Temporal can automatically retry it until it succeeds or reaches a specified retry limit. This ensures that transient issues, like network glitches or temporary service outages, don't result in data loss or incomplete processes.
-For this tutorial, you'll define Activities for tasks like charging customers and sending emails, which typically interact with external services. To keep things focused on the Workflow logic, you will stub these Activities out with basic `log` statements.
+For this tutorial, you'll define Activities for tasks like charging customers and sending emails, which typically interact with external services. To keep things focused on the Workflow logic, you will stub these Activities out with basic `log` statements.
First, create the function that sends the Welcome email. Add the following code to `src/activities.ts`:
@@ -220,7 +220,7 @@ As you can see, an Activity in Temporal is just like writing your typical TypeSc
The Temporal SDK also provides plenty of packages like a logging package which makes it easier to follow your code's execution path at runtime.
-Next, you will add a few more functions that sends e-mails that do the following:
+Next, you will add a few more functions that sends e-mails that do the following:
- Send a cancellation e-mail during the trial period.
- Send a notification to the customer, letting the customer know that he or she will be charged for the billing period.
- Send a cancellation e-mail during an active subscription.
@@ -313,9 +313,9 @@ Now that you have configured retries with your Activities, you can move onto wri
1. Check if the subscription was canceled during the trial period. If so, you want to call your `sendCancellationEmailDuringTrialPeriod` Activity.
-2. If the subscription wasn't canceled during the trial period, you want to start billing the customer until you reach the max billing periods or the subscription is cancelled.
+2. If the subscription wasn't canceled during the trial period, you want to start billing the customer until you reach the max billing periods or the subscription is cancelled.
-3. If the subscription is cancelled or the billing period is complete during this time, you want to call your `sendSubscriptionFinishedEmail` Activity.
+3. If the subscription is cancelled or the billing period is complete during this time, you want to call your `sendSubscriptionFinishedEmail` Activity.
4. Finally, if the subscription period is over and not canceled, notify the customer to buy a new subscription by calling the `sendSubscriptionOverEmail` Activity. Then return with a statement letting the subscription owner know that particular Workflow Execution is complete, and the total amount charged.
@@ -381,7 +381,7 @@ Now that you have your subscription Workflow, you will now run it.
The first step to run anything in Temporal is to make sure you have a local Temporal Service running. Open a separate terminal window and start the service with `temporal server start-dev`.
-As you will see in the command line output, your Temporal Server should now be running on `http://localhost:8233`. When you first access this server, you should see zero Workflows running.
+As you will see in the command line output, your Temporal Server should now be running on `http://localhost:8233`. When you first access this server, you should see zero Workflows running.
The next step is to define your Worker program in `worker.ts`.
@@ -419,7 +419,7 @@ run().catch((err) => {
```
-First, you register the Workflows and Activities with the Worker program.
+First, you register the Workflows and Activities with the Worker program.
Then, you start accepting the tasks that will route to the Task Queue that your Worker is registered with, which is `subscriptions-task-queue` defined in the `shared.ts` file.
Run the Worker now with the script defined in `package.json` to run your `worker.ts` file and make sure that everything builds and there are no errors. You should run the Worker Program with a new terminal window:
@@ -571,7 +571,7 @@ Save your file and run your Workflow again with `npm run workflow`. This time, a
Also, notice in the command-line window that your Worker is running, the Activity logs are being output: `Sending welcome email to email-1@customer.com`, `Charging email-1@customer.com amount 130 for their billing period`, and the other logs.
-Now that you know how to run your `subscriptionWorkflow`, you will look into how to query your Workflow to retrieve information such as the billing period and the total amount charged. This allows you to interact with the Workflow while it's running and get real-time updates on its status and progress.
+Now that you know how to run your `subscriptionWorkflow`, you will look into how to query your Workflow to retrieve information such as the billing period and the total amount charged. This allows you to interact with the Workflow while it's running and get real-time updates on its status and progress.
## Retrieve subscription details
@@ -602,7 +602,7 @@ After defining a Query, the next step is to establish how the Workflow handles i
Use the [`setHandler`](https://typescript.temporal.io/api/namespaces/workflow/#sethandler) function provided by the Temporal TypeScript SDK API. This function associates each Query with its corresponding handler logic.
-Within the `workflows.ts` file, add `setHandler` to your list of imports from `@temporalio/workflow`.
+Within the `workflows.ts` file, add `setHandler` to your list of imports from `@temporalio/workflow`.
Then, within your `subscriptionWorkflow` Workflow right before you call the `sendWelcomeEmail` Activity, use `setHandler` to handle your Queries as follows:
@@ -642,7 +642,7 @@ This code defines two Signals:
However, like Queries, just defining a Signal is the first step. You also need to let the Workflow know what to do when it receives a Signal of that type. This is done using a Signal Handler, which is a function within the Workflow that listens for incoming Signals of a specified type and defines the Workflow's response.
-In order to implement a Signal handler, recall that the [`setHandler`](https://typescript.temporal.io/api/namespaces/workflow/#sethandler) function associates each Signal with its corresponding handler logic.
+In order to implement a Signal handler, recall that the [`setHandler`](https://typescript.temporal.io/api/namespaces/workflow/#sethandler) function associates each Signal with its corresponding handler logic.
Within the `workflows.ts` file and within the `subscriptionWorkflow` Workflow Definition, implement the Signal handlers as shown:
@@ -719,45 +719,45 @@ And replace it with:
[src/workflows.ts](https://github.com/temporalio/subscription-workflow-project-template-typescript/blob/main/src/workflows.ts)
```ts
// ...
-// Used to wait for the subscription to be cancelled or for a trial period timeout to elapse
-if (
- await condition(
- () => subscriptionCancelled,
- customer.subscription.trialPeriod
- )
-) {
- await sendCancellationEmailDuringTrialPeriod(customer);
- return `Subscription finished for: ${customer.id}`;
-} else {
- // Trial period is over, start billing until we reach the max billing periods for the subscription or subscription has been cancelled
- while (true) {
- if (billingPeriodNumber > customer.subscription.maxBillingPeriods) break;
+ // Used to wait for the subscription to be cancelled or for a trial period timeout to elapse
+ if (
+ await condition(
+ () => subscriptionCancelled,
+ customer.subscription.trialPeriod
+ )
+ ) {
+ await sendCancellationEmailDuringTrialPeriod(customer);
+ return `Subscription finished for: ${customer.id}`;
+ } else {
+ // Trial period is over, start billing until we reach the max billing periods for the subscription or subscription has been cancelled
+ while (true) {
+ if (billingPeriodNumber > customer.subscription.maxBillingPeriods) break;
- if (subscriptionCancelled) {
- await sendSubscriptionFinishedEmail(customer);
- return `Subscription finished for: ${customer.id}, Total Charged: ${totalCharged}`;
- }
+ if (subscriptionCancelled) {
+ await sendSubscriptionFinishedEmail(customer);
+ return `Subscription finished for: ${customer.id}, Total Charged: ${totalCharged}`;
+ }
- log.info(`Charging ${customer.id} amount ${billingPeriodChargeAmount}`);
+ log.info(`Charging ${customer.id} amount ${billingPeriodChargeAmount}`);
- await chargeCustomerForBillingPeriod(customer, billingPeriodChargeAmount);
- totalCharged += billingPeriodChargeAmount;
- billingPeriodNumber++;
+ await chargeCustomerForBillingPeriod(customer, billingPeriodChargeAmount);
+ totalCharged += billingPeriodChargeAmount;
+ billingPeriodNumber++;
- // Wait for the next billing period or until the subscription is cancelled
- await sleep(customer.subscription.billingPeriod);
- }
+ // Wait for the next billing period or until the subscription is cancelled
+ await sleep(customer.subscription.billingPeriod);
+ }
- // If the subscription period is over and not cancelled, notify the customer to buy a new subscription
- await sendSubscriptionOverEmail(customer);
- return `Completed ${
- workflowInfo().workflowId
- }, Total Charged: ${totalCharged}`;
-}
+ // If the subscription period is over and not cancelled, notify the customer to buy a new subscription
+ await sendSubscriptionOverEmail(customer);
+ return `Completed ${
+ workflowInfo().workflowId
+ }, Total Charged: ${totalCharged}`;
+ }
```
-In the code, the `condition` method pauses the Workflow until either the `subscriptionCancelled` flag is true (meaning a `cancelSubscription` Signal was received) or the trial period expires. Once the condition is met, the Workflow invokes the Activity to send a cancellation email.
+In the code, the `condition` method pauses the Workflow until either the `subscriptionCancelled` flag is true (meaning a `cancelSubscription` Signal was received) or the trial period expires. Once the condition is met, the Workflow invokes the Activity to send a cancellation email.
In the loop that iterates through the billing period, the loop checks constantly as well for the `subscriptionCancelled` flag to be `true`.
@@ -827,15 +827,15 @@ Start by initiating the Workflow Execution and getting the handle:
[src/scripts/cancel-subscription.ts](https://github.com/temporalio/subscription-workflow-project-template-typescript/blob/main/src/scripts/cancel-subscription.ts)
```ts
// ...
-const subscriptionWorkflowExecution = await client.workflow.start(
- subscriptionWorkflow,
- {
- args: [customer],
- taskQueue: TASK_QUEUE_NAME,
- workflowId: `subscription-${customer.id}`,
- }
-);
-const handle = await client.workflow.getHandle(`subscription-${customer.id}`);
+ const subscriptionWorkflowExecution = await client.workflow.start(
+ subscriptionWorkflow,
+ {
+ args: [customer],
+ taskQueue: TASK_QUEUE_NAME,
+ workflowId: `subscription-${customer.id}`,
+ }
+ );
+ const handle = await client.workflow.getHandle(`subscription-${customer.id}`);
```
@@ -957,7 +957,7 @@ You now know how to obtain a handle on a Workflow Execution and send a Signal to
## Retrieve billing period and total charged details
-You will now retrieve details about the billing period and total amount charged. You have already defined and handled your Query. You will now send a Query through the Client to retrieve information from a running or completed Workflow. The SDK provides the `WorkflowHandle.query` method to query a running or completed Workflow, allowing you to access details of the `subscriptionWorkflow`, without interrupting its execution.
+You will now retrieve details about the billing period and total amount charged. You have already defined and handled your Query. You will now send a Query through the Client to retrieve information from a running or completed Workflow. The SDK provides the `WorkflowHandle.query` method to query a running or completed Workflow, allowing you to access details of the `subscriptionWorkflow`, without interrupting its execution.
Since this Client code will focus on querying the billing info, in the `query-billinginfo.ts` file, first reuse the customer object:
@@ -1049,8 +1049,8 @@ You now know how to obtain a handle on a Workflow Execution and send a Query to
## Conclusion
-By using Temporal, you were able to build a fault-tolerant subscription Workflow that manages complex state transitions and interactions with external services. Temporal's durable execution and automatic state persistence ensured that your Workflow could reliably handle user sign-ups, trial periods, billing cycles, and cancellations, even in the face of failures or interruptions.
+By using Temporal, you were able to build a fault-tolerant subscription Workflow that manages complex state transitions and interactions with external services. Temporal's durable execution and automatic state persistence ensured that your Workflow could reliably handle user sign-ups, trial periods, billing cycles, and cancellations, even in the face of failures or interruptions.
The ability to send Signals and Queries allowed for dynamic interaction with running Workflows, making real-time updates and state retrieval straightforward and maintainable. With Temporal, you can simplify the management of long-running business processes, and create scalable and fault-tolerant applications.
-As a next step, try using [Express.js](https://expressjs.com/) to build an API for your application. The code you used in the command-line scripts can be adapted for your API endpoints, enabling more seamless and user-friendly interactions with your Temporal Workflow Executions.
\ No newline at end of file
+As a next step, try using [Express.js](https://expressjs.com/) to build an API for your application. The code you used in the command-line scripts can be adapted for your API endpoints, enabling more seamless and user-friendly interactions with your Temporal Workflow Executions.
diff --git a/docs/tutorials/typescript/work-queue-slack-app/build/index.mdx b/docs/tutorials/typescript/work-queue-slack-app/build/index.mdx
index 627062ae..20dbeba5 100644
--- a/docs/tutorials/typescript/work-queue-slack-app/build/index.mdx
+++ b/docs/tutorials/typescript/work-queue-slack-app/build/index.mdx
@@ -264,9 +264,7 @@ Next, define the common types used across the application.
Create a file `types.ts` in the `common-types` directory and define a Work Item data object and its statuses:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/common-types/types.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/common-types/types.ts)
-
```ts
export interface WorkqueueData {
id: string;
@@ -286,7 +284,6 @@ export enum WorkqueueStatus {
Done = 3,
}
```
-
Now that that is set up, you can start building the Work Queue Workflow.
@@ -325,22 +322,20 @@ As you add and remove work items from the Work Queue, the Event History grows.
When you continue the Workflow as a new one, you will pass the latest Work Queue data to the new Workflow instance, leaving the old Event History behind, but retaining the state of the Work Queue.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/workflows/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/workflows/workqueue.ts)
-
```ts
import {
isCancellation,
continueAsNew,
workflowInfo,
condition,
- // ...
+// ...
} from "@temporalio/workflow";
import {WorkqueueData} from "../../../common-types/types";
// ...
export async function workqueue(existingData?: WorkqueueData[]): Promise {
const wqdata: WorkqueueData[] = existingData ?? [];
- // ...
+// ...
try {
// Await until suggestion to Continue-As-New due to History size
// If a Cancellation request exists, the condition call will throw the Cancellation error
@@ -358,7 +353,6 @@ export async function workqueue(existingData?: WorkqueueData[]): Promise {
await continueAsNew(wqdata);
}
```
-
What's also handy about the `condition` API is that if there is a Cancellation request, the condition call will throw a Cancellation error.
@@ -379,12 +373,10 @@ You will use a Query to get the current state of the Work Queue.
It is a good practice to define the Signals and Queries outside of the Workflow and handle them right after declaring local state variables within the Workflow.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/workflows/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/workflows/workqueue.ts)
-
```ts
import {
- // ...
+// ...
defineQuery,
defineSignal,
setHandler,
@@ -400,7 +392,7 @@ export const completeWorkSignal =
defineSignal<[{workId: string}]>("completeWork");
export async function workqueue(existingData?: WorkqueueData[]): Promise {
- // ...
+// ...
// Register a Query handler for 'getWorkqueueData'
setHandler(getWorkqueueDataQuery, () => {
return wqdata;
@@ -427,10 +419,9 @@ export async function workqueue(existingData?: WorkqueueData[]): Promise {
wqdata.splice(index, 1);
}
});
- // ...
+// ...
}
```
-
Now, register your Workflow with a Temporal Worker.
@@ -442,9 +433,7 @@ You need the Worker code to run your Workflow code.
If you don't already have it, create `worker.ts` inside of `temporal-application/src` and add the following code:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/dev-worker.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/dev-worker.ts)
-
```ts
import "dotenv/config";
import path from "path";
@@ -467,7 +456,6 @@ async function run() {
run();
```
-
Make sure your `package.json` file in the `temporal-application` project has a script to run the Worker:
@@ -506,9 +494,7 @@ Your main `slack_bot.ts` file will initialize the Slack App and the Temporal Cli
First, you will need to create and export a Temporal Client in `bot/modules/temporal-client.ts`.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/dev-temporal-client.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/dev-temporal-client.ts)
-
```ts
import "dotenv/config";
import {Client, Connection} from "@temporalio/client";
@@ -524,7 +510,6 @@ export async function initializeTemporalClient() {
});
}
```
-
Now, you can initialize the Slack App in `bot/slack_bot.ts`.
@@ -532,14 +517,12 @@ Now, you can initialize the Slack App in `bot/slack_bot.ts`.
In the root of the `bot` project, create a file called `slack_bot.ts` and initialize the Slack bot, making sure to import and initialize the Temporal Client module:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/slack_bot.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/slack_bot.ts)
-
```ts
import "dotenv/config";
import {
App,
- // ...
+// ...
} from "@slack/bolt";
import {initializeTemporalClient} from "./modules/dev-temporal-client";
// ...
@@ -571,7 +554,6 @@ app.error(async ({error}: {error: Error}) => {
}
})();
```
-
Now, you can create the `workqueue` module that interact with the Work Queue Workflow.
@@ -582,16 +564,14 @@ This is where a majority of the Slack Command, work claiming, and work completin
Here you will export a function that looks at the command text and decides what to do based on the text.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts)
-
```ts
// ...
import {
SayFn,
RespondFn,
SlackCommandMiddlewareArgs,
- // ...
+// ...
} from "@slack/bolt";
import {WorkqueueData, WorkqueueStatus} from "../../common-types/types";
import {temporalClient} from "./dev-temporal-client";
@@ -616,7 +596,6 @@ export async function handleWorkqueueCommand(
return;
}
```
-
In the preceeding snippet you can see that the there are three possible ways to use the `workqueue` Slash Command.
@@ -635,9 +614,7 @@ If it does, then in this case you will just ignore the error and Query the Workf
Define three functions, `displayWorkQueue`, `createNewWorkqueue`, and `queryWorkqueue` in the `workqueue.ts` module.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts)
-
```ts
// ...
// Display the Work Queue for the channel
@@ -692,7 +669,6 @@ async function queryWorkQueue(
}
}
```
-
In the preceding snippet, the `createNewWorkqueue` function attempts to start a new Work Queue Workflow.
@@ -708,9 +684,7 @@ This function needs to build the Work Item data object and call another function
Click the link at the top of the code snippet to visit the source code and see the full code implementation for building the Work Item data object.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts)
-
```ts
// ...
// Add work to the queue using a Signal
@@ -741,7 +715,6 @@ async function signalAddWork(params: WorkqueueData, say: SayFn): Promise {
}
}
```
-
The key part of this functionality is using the Temporal Client's `signalWithStart` API.
@@ -753,15 +726,13 @@ Next, implement the functionality that will allow a user to claim a work item fr
In the `slack_bot.ts` file, you will need to add a listener for the `wq_claim` button click event.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/slack_bot.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/slack_bot.ts)
-
```ts
// ...
import {
- // ...
+// ...
signalClaimWork,
- // ...
+// ...
} from "./modules/workqueue";
// ...
// Listen for Work Item Claim
@@ -782,15 +753,12 @@ app.action>(
}
);
```
-
Then, in `workqueue.ts` module, define a `claimWork` function that sends a Signal to the Work Queue Workflow to claim the work item.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts)
-
```ts
// ...
export async function signalClaimWork(
@@ -813,7 +781,6 @@ export async function signalClaimWork(
}
}
```
-
When someone finishes working on the task they will need to be able to mark it as complete.
@@ -821,13 +788,11 @@ When someone finishes working on the task they will need to be able to mark it a
In the `slack_bot.ts` file, you will need to add a listener for the`wq_complete` button click event.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/slack_bot.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/slack_bot.ts)
-
```ts
// ...
import {
- // ...
+// ...
signalCompleteWork,
} from "./modules/workqueue";
// ...
@@ -848,15 +813,12 @@ app.action>(
}
);
```
-
Then, in the `workqueue.ts` module, define a function `completeWork` that sends a Signal to the Work Queue Workflow to mark the work item as complete.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts)
-
```ts
// ...
export async function signalCompleteWork(
@@ -876,7 +838,6 @@ export async function signalCompleteWork(
}
}
```
-
Lastly, you will want to have the compatibility to delete a Work Queue for the channel.
@@ -887,9 +848,7 @@ To send a Cancellation Request, in the `workqueue.ts` module, define a function
This Slack App assumes that the Slack channel name is unique and therefor can be used as the Workflow ID.
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/workqueue.ts)
-
```ts
// ...
// Delete the Work Queue for the channel with a Cancellation Request
@@ -909,7 +868,6 @@ export async function deleteWorkqueue(
}
}
```
-
By using the Slack channel name as the Workflow ID, you can tell which Workflow corresponds to which channel in the Temporal UI if you need to do any debugging.
@@ -971,9 +929,7 @@ The Temporal TypeScript SDK comes equipped with a Test Suite and a pattern for t
Set up the Test Suite like this:
-
-[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/**tests**/workqueue.test.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/__tests__/workqueue.test.ts)
-
+[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/__tests__/workqueue.test.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/__tests__/workqueue.test.ts)
```ts
import {TestWorkflowEnvironment} from "@temporalio/testing";
import {WorkflowCoverage} from "@temporalio/nyc-test-coverage";
@@ -995,10 +951,9 @@ describe("Work Queue Workflow", () => {
afterAll(() => {
workflowCoverage.mergeIntoGlobalCoverage();
});
- // ...
+// ...
});
```
-
You can test for many scenarios.
@@ -1012,43 +967,40 @@ For example, you could test for the following:
The basic pattern to test adding work to the Work Queue looks like this:
-
-[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/**tests**/workqueue.test.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/__tests__/workqueue.test.ts)
-
+[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/__tests__/workqueue.test.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/__tests__/workqueue.test.ts)
```ts
// ...
-test("should add work to the queue", async () => {
- // Get a test environment Temporal Client
- const {client, nativeConnection} = testEnv;
- // Create a test environment Worker
- const worker = await Worker.create(
- workflowCoverage.augmentWorkerOptions({
- connection: nativeConnection,
- taskQueue: "test",
- workflowsPath: require.resolve("../workflows"),
- })
- );
- // ...
- // Run the Worker
- await worker.runUntil(async () => {
- const handle = await client.workflow.start(workqueue, {
- args: [],
- workflowId: workflowId,
- taskQueue: "test",
+ test("should add work to the queue", async () => {
+ // Get a test environment Temporal Client
+ const {client, nativeConnection} = testEnv;
+ // Create a test environment Worker
+ const worker = await Worker.create(
+ workflowCoverage.augmentWorkerOptions({
+ connection: nativeConnection,
+ taskQueue: "test",
+ workflowsPath: require.resolve("../workflows"),
+ })
+ );
+// ...
+ // Run the Worker
+ await worker.runUntil(async () => {
+ const handle = await client.workflow.start(workqueue, {
+ args: [],
+ workflowId: workflowId,
+ taskQueue: "test",
+ });
+ const workItem: WorkqueueData = {
+// ...
+ };
+ // Add work to the queue
+ await handle.signal(addWorkToQueueSignal, workItem);
+ // Check to see if the data is there
+ const result = await handle.query(getWorkqueueDataQuery);
+ // Compare the data
+ expect(result).toContainEqual(workItem);
});
- const workItem: WorkqueueData = {
- // ...
- };
- // Add work to the queue
- await handle.signal(addWorkToQueueSignal, workItem);
- // Check to see if the data is there
- const result = await handle.query(getWorkqueueDataQuery);
- // Compare the data
- expect(result).toContainEqual(workItem);
});
-});
```
-
For more test examples, see the Work Queue Workflow test file by clicking the link at the top of the preceding code snippet.
diff --git a/docs/tutorials/typescript/work-queue-slack-app/deploy/index.mdx b/docs/tutorials/typescript/work-queue-slack-app/deploy/index.mdx
index 47e57b93..2d88449e 100644
--- a/docs/tutorials/typescript/work-queue-slack-app/deploy/index.mdx
+++ b/docs/tutorials/typescript/work-queue-slack-app/deploy/index.mdx
@@ -81,9 +81,7 @@ You will need to update your Temporal Client and your Temporal Worker code.
When developing locally, your Temporal Client, located in `bot/modules/temporal-client.ts`, looks like this:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/dev-temporal-client.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/dev-temporal-client.ts)
-
```ts
import "dotenv/config";
import {Client, Connection} from "@temporalio/client";
@@ -99,16 +97,13 @@ export async function initializeTemporalClient() {
});
}
```
-
To use Temporal Cloud, change the Temporal Client code to read your Namespace certificate key and pem env variables.
Then change the connection object to includes the Namespace and certificate information:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/cloud-temporal-client.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/bot/modules/cloud-temporal-client.ts)
-
```ts
import "dotenv/config";
import {Client, Connection} from "@temporalio/client";
@@ -136,7 +131,6 @@ export async function initializeTemporalClient() {
});
}
```
-
Then update the code for the Temporal Worker to change how it connects.
@@ -144,9 +138,7 @@ Then update the code for the Temporal Worker to change how it connects.
When developing locally, your Temporal Worker, located in `temporal-application/src/worker.ts`, looks like this:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/dev-worker.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/dev-worker.ts)
-
```ts
import "dotenv/config";
import path from "path";
@@ -169,7 +161,6 @@ async function run() {
run();
```
-
To use Temporal Cloud, you'll change the connection information for your Worker in the same way you changed your client.
@@ -177,9 +168,7 @@ Read the certificate env variables and update the connection object to include t
Alter the `worker.ts` file so it looks like the following:
-
[docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/cloud-worker.ts](https://github.com/temporalio/temporal-learning/blob/edu-2636-workqueue-slackbot-tut/docs/tutorials/typescript/work-queue-slack-app/build/code/temporal-application/src/cloud-worker.ts)
-
```ts
import "dotenv/config";
import path from "path";
@@ -218,7 +207,6 @@ async function run() {
run();
```
-
You can now run your application locally to ensure it works with Temporal Cloud.
diff --git a/docs/tutorials/typescript/work-queue-slack-app/index.mdx b/docs/tutorials/typescript/work-queue-slack-app/index.mdx
index cf602c4c..e8d6cc86 100644
--- a/docs/tutorials/typescript/work-queue-slack-app/index.mdx
+++ b/docs/tutorials/typescript/work-queue-slack-app/index.mdx
@@ -17,5 +17,5 @@ When you are building a TypeScript application, you will typically build it loca
In this two-part tutorial, you will first build a Work Queue Slack App with TypeScript and Temporal locally on your machine using the Temporal CLI.
Then, you will deploy it to production on a DigitalOcean Droplet using Temporal Cloud.
-- [Build a Work Queue Slack App with TypeScript and Temporal](/tutorials/typescript/work-queue-slack-app/build)
+- [Build a Work Queue Slack App with TypeScript](/tutorials/typescript/work-queue-slack-app/build)
- [Deploy a Typescript Slack App with TypeScript to DigitalOcean using Temporal Cloud](/tutorials/typescript/work-queue-slack-app/deploy)
diff --git a/vercel.json b/vercel.json
index 1e9c7bc3..38adca53 100644
--- a/vercel.json
+++ b/vercel.json
@@ -1,3 +1,50 @@
{
- "trailingSlash": true
+ "trailingSlash": true,
+ "redirects": [
+ {
+ "source": "/tutorials/go/ecommerce/",
+ "destination": "/tutorials/go/build-an-ecommerce-app/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/go/subscriptions/",
+ "destination": "/tutorials/go/build-an-email-drip-campaign/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/php/booking_saga/",
+ "destination": "/tutorials/php/build_a_trip_booking_app/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/php/subscriptions/",
+ "destination": "/tutorials/php/build-a-recurring-billing-app/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/python/subscriptions/",
+ "destination": "/tutorials/python/build-an-email-drip-campaign/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/python/data-pipelines/",
+ "destination": "/tutorials/python/build-a-data-pipeline/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/typescript/nextjs/",
+ "destination": "/tutorials/typescript/build-one-click-order-app-nextjs/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/typescript/subscriptions/",
+ "destination": "/tutorials/typescript/recurring-billing-system/",
+ "permanent": true
+ },
+ {
+ "source": "/tutorials/typescript/chatbot/",
+ "destination": "/tutorials/typescript/build-choose-your-own-adventure-bot/",
+ "permanent": true
+ }
+ ]
}