Skip to main content
Temporal TypeScript SDK

Build a Choose Your Own Adventure Bot in TypeScript

~45 minutesTypeScriptIntermediate
Outdated

This tutorial may reference older versions of the SDK or supporting tools.

Introduction

In this tutorial, you'll integrate all the knowledge gained from Core and Logging APIs in an end-to-end demo application - a Choose Your Own Adventure game that you can play on Discord or Slack.

This project integrates and gives context to your understanding of Temporal SDK APIs: logging with Sinks, Activity dependency injection, Timer and Promise.race design patterns, Signals (and HTTP Servers for them), Polling patterns, and continueAsNew for indefinitely long running Workflows.

Skip ahead

View the completed project on GitHub: https://github.com/JoshuaKGoldberg/temporal-adventure-bot

Prerequisites

Project Requirements

  • On /instructions, posts instructions to Slack/Discord and pins the message.
  • Continuously runs the game until it reaches an end state:
    • Every day, post the current entry as a poll.
    • Wait until the earlier of:
      • Every day, check the poll results
        • If there is consensus, determine next state.
        • If no consensus, remind people to vote.
      • Allow an admin to /force a choice at any time.
  • Report important game updates to a specified logger.

Companion video walkthrough: YouTube.

  • 00:00 Project Intro and Demo
  • 03:30 Temporal Worker - Activity Dependency Injection
  • 07:00 Temporal Sinks for Logging
  • 08:00 Temporal Client
  • 10:50 RunGame Workflow and Game Logic
  • 13:45 Async Race Design Pattern: Timers vs Humans
  • 15:00 Design Pattern: Polling
  • 18:05 Signals
  • 20:00 HTTP Server for Signal
  • 23:00 ContinueAsNew

Overview

Worker

The Temporal Worker is set up in src/worker.ts. It uses two common Temporal patterns:

  • Dependency Injection: using the integration object created by createIntegration to provide APIs for the social platform being targeted (Discord or Slack).
  • Logging Sinks: providing a logger.sink method for the Workflows to log out to console.log.

Client

The client in src/client.ts will ask Temporal to run two different Workflows:

  1. instructions: Posts instructions to the social platform and pins the message.
  2. runGame: Continuously runs the game state until the game is finished.

runGame

Each iteration of the game (daily), runGame goes through these steps:

  1. If the entry has no options, the game is over.
  2. Post the current entry as a poll.
  3. Check and remind people to vote once a day until either:
    • a choice is made by consensus.
    • an admin forces a choice.
  4. If the choice was forced by an admin, mention that.
  5. Continue with that chosen next step in the game.

Platforms

The platformFactory function used in both workers and Workflows reads from process.env to return the createIntegration and createServer methods for the social platform being targeted.

Integrations

createIntegration creates the client API used to send messages to the social platform. For example, the Slack integration uses the Slack Bolt SDK.

Servers

createServer creates the (generally Express) server that runs locally and receives webhook events from the social platform. Both the Discord and Slack servers use Ngrok to expose a local port on the public web, so that a /force command configured on the platform can Signal to the Workflow.

Get notified when we launch new educational content

New courses, tutorials, and learning resources - straight to your inbox.

Subscribe
Feedback