Skip to main content

Temporal "Hello World!" app in TypeScript

WORK IN PROGRESS

This tutorial is a work in progress. Some sections may be incomplete, out of date, or missing. We're working to update it.

Introduction

In this tutorial, you'll explore the different components that make up a Temporal project using the TypeScript SDK. The SDK steers developers to write Workflows and Activities in TypeScript but vanilla JS is also supported.

Prerequisites

Define a Workflow

In the TypeScript SDK, each Workflow execution is run in a separate V8 isolated context in order to provide a deterministic runtime.

A Workflow is also an async function, but it has access to special Workflow APIs like Signals, Queries, Timers, and Child Workflows.

The following snippet uses proxyActivities to create a function that, when called, schedules an Activity in the system:

src/workflows.ts

hello-world/src/workflows.ts

import { proxyActivities } from '@temporalio/workflow';
// Only import the activity types
import type * as activities from './activities';

const { greet } = proxyActivities<typeof activities>({
startToCloseTimeout: '1 minute',
});

/** A workflow that simply calls an activity */
export async function example(name: string): Promise<string> {
return await greet(name);
}

@temporalio/workflow API reference

Define an activity

Activities are called from Workflows in order to run non-deterministic code.

@temporalio/activity API reference

Any async function can be used as an Activity as long as its parameters and return value are serializable. Activities run in the Node.js execution environment, meaning you can easily port over any existing code into an Activity and it should work.

src/activities.ts

hello-world/src/activities.ts

export async function greet(name: string): Promise<string> {
return `Hello, ${name}!`;
}

Worker

@temporalio/worker API reference

The Worker hosts Workflows and Activities, connects to Temporal Server, and continually polls a Task Queue for Commands coming from Clients (see below). See the list of WorkerOptions for customizing Worker creation.

src/worker.ts

hello-world/src/worker.ts

import { Worker } from '@temporalio/worker';
import * as activities from './activities';

async function run() {
// Step 1: Register Workflows and Activities with the Worker and connect to
// the Temporal server.
const worker = await Worker.create({
workflowsPath: require.resolve('./workflows'),
activities,
taskQueue: 'hello-world',
});
// Worker connects to localhost by default and uses console.error for logging.
// Customize the Worker by passing more options to create():
// https://typescript.temporal.io/api/classes/worker.Worker
// If you need to configure server connection parameters, see docs:
// https://docs.temporal.io/typescript/security#encryption-in-transit-with-mtls

// Step 2: Start accepting tasks on the `hello-world` queue
await worker.run();
}

run().catch((err) => {
console.error(err);
process.exit(1);
});

Client

@temporalio/client API reference

The WorkflowClient class is used to interact with existing Workflows or to start new ones.

It can be used in any Node.js process (for example, an Express web server) and is separate from the Worker.

src/client.ts

hello-world/src/client.ts

import { Connection, WorkflowClient } from '@temporalio/client';
import { example } from './workflows';
import { nanoid } from 'nanoid';

async function run() {
const connection = await Connection.connect({
// // Connect to localhost with default ConnectionOptions.
// // In production, pass options to the Connection constructor to configure TLS and other settings:
// address: 'foo.bar.tmprl.cloud', // as provisioned
// tls: {} // as provisioned
});

const client = new WorkflowClient({
connection,
// namespace: 'default', // change if you have a different namespace
});

const handle = await client.start(example, {
args: ['Temporal'], // type inference works! args: [name: string]
taskQueue: 'hello-world',
// in practice, use a meaningful business id, eg customerId or transactionId
workflowId: 'workflow-' + nanoid(),
});
console.log(`Started workflow ${handle.workflowId}`);

// optional: wait for client result
console.log(await handle.result()); // Hello, Temporal!
}

run().catch((err) => {
console.error(err);
process.exit(1);
});

Testing

There is no official test suite for Workflows and Activities yet.

  • Since Activities are async functions, they should be testable as long as you avoid using Context or are able to mock it.
  • You can test Workflows by running them with a WorkflowClient.
  • Check the SDK's own tests for more examples.

Conclusion

You should now be familiar with the Hello World project, which is the main way we encourage scaffolding out new projects.

Dive deeper into developing with TypeScript with the following tutorials: