← Files TemporalARCHIVED FILE

skills/temporal-developer/references/typescript/advanced-features.md

5.6 KB · Oct 2, 2026 · 00:08 UTC

↓ Download file

# TypeScript SDK Advanced Features

## Schedules

Create recurring workflow executions.

```typescript
import { Client, ScheduleOverlapPolicy } from '@temporalio/client';

const client = new Client();

// Create a schedule
const schedule = await client.schedule.create({
  scheduleId: 'daily-report',
  spec: {
    intervals: [{ every: '1 day' }],
  },
  action: {
    type: 'startWorkflow',
    workflowType: 'dailyReportWorkflow',
    taskQueue: 'reports',
    args: [],
  },
  policies: {
    overlap: ScheduleOverlapPolicy.SKIP,
  },
});

// Manage schedules
const handle = client.schedule.getHandle('daily-report');
await handle.pause('Maintenance window');
await handle.unpause();
await handle.trigger();  // Run immediately
await handle.delete();
```

## Async Activity Completion

Complete an activity asynchronously from outside the activity function. Useful when the activity needs to wait for an external event.

**In the activity - return the task token:**

```typescript
import { CompleteAsyncError, activityInfo } from '@temporalio/activity';

export async function doSomethingAsync(): Promise<string> {
  const taskToken: Uint8Array = activityInfo().taskToken;
  setTimeout(() => doSomeWork(taskToken), 1000);
  throw new CompleteAsyncError();
}
```

**External completion (from another process, machine, etc.):**

```typescript
import { Client } from '@temporalio/client';

async function doSomeWork(taskToken: Uint8Array): Promise<void> {
  const client = new Client();
  // does some work...
  await client.activity.complete(taskToken, "Job's done!");
}
```

**When to use:**

- Waiting for human approval
- Waiting for external webhook callback
- Long-polling external systems

## Worker Tuning

Configure worker capacity for production workloads:

```typescript
import { Worker, NativeConnection } from '@temporalio/worker';

const worker = await Worker.create({
  connection: await NativeConnection.connect({ address: 'temporal:7233' }),
  taskQueue: 'my-queue',
  workflowBundle: { codePath: require.resolve('./workflow-bundle.js') }, // Pre-bundled for production
  activities,

  // Workflow execution concurrency (default: 40)
  maxConcurrentWorkflowTaskExecutions: 100,

  // Activity execution concurrency (default: 100)
  maxConcurrentActivityTaskExecutions: 200,

  // Graceful shutdown timeout (default: 0)
  shutdownGraceTime: '30 seconds',

  // Max cached workflows (memory vs latency tradeoff)
  maxCachedWorkflows: 1000,
});
```

**Key settings:**

- `maxConcurrentWorkflowTaskExecutions`: Max workflows running simultaneously (default: 40)
- `maxConcurrentActivityTaskExecutions`: Max activities running simultaneously (default: 100)
- `shutdownGraceTime`: Time to wait for in-progress work before forced shutdown
- `maxCachedWorkflows`: Number of workflows to keep in cache (reduces replay on cache hit)

## Preload Modules

`preloadModules`  is a `string[]` bundler option that loads a list of modules once during reusable V8 context bootstrap; preloaded modules are then shared across workflows executing in the same V8 context.  It is only beneficial when `reuseV8Context` is enabled, which is the default (`@default true`).

**Ahead-of-time bundling via `BundleOptions`:**

```typescript
import { bundleWorkflowCode } from '@temporalio/worker';

const { code } = await bundleWorkflowCode({
  workflowsPath: require.resolve('./workflows'),
  preloadModules: ['lodash', './workflow-helpers'],
});
```

**Startup bundling via `WorkerOptions.bundlerOptions`:**

```typescript
const worker = await Worker.create({
  taskQueue: 'my-queue',
  workflowsPath: require.resolve('./workflows'),
  activities,
  bundlerOptions: {
    preloadModules: ['lodash', './workflow-helpers'],
  },
});
```

**Constraints:**

- **`preloadModules` is only beneficial when `reuseV8Context` is enabled (default `true`). ** If `reuseV8Context` is disabled, leave the list empty.
- **Module top-level code runs once, before any workflow activator exists. ** Only preload modules whose initialization is safe to execute that early.
- **Preloading a module that internally stores per-workflow state will leak context across workflows and cause non-deterministic behavior. ** Remove such modules from `preloadModules`.
- **A module listed in both `preloadModules` and `ignoreModules` fails the bundle with `Cannot preload modules that are also ignored: '<module>'`. ** Remove the module from one of the two lists.

## Sinks

Sinks allow workflows to emit events for side effects (logging, metrics).

```typescript
import { proxySinks, Sinks } from '@temporalio/workflow';

// Define sink interface
export interface LoggerSinks extends Sinks {
  logger: {
    info(message: string, attrs: Record<string, unknown>): void;
    error(message: string, attrs: Record<string, unknown>): void;
  };
}

// Use in workflow
const { logger } = proxySinks<LoggerSinks>();

export async function myWorkflow(input: string): Promise<string> {
  logger.info('Workflow started', { input });

  const result = await someActivity(input);

  logger.info('Workflow completed', { result });
  return result;
}

// Implement sink in worker
const worker = await Worker.create({
  workflowsPath: require.resolve('./workflows'), // Use workflowBundle for production
  activities,
  taskQueue: 'my-queue',
  sinks: {
    logger: {
      info: {
        fn(workflowInfo, message, attrs) {
          console.log(`[${workflowInfo.workflowId}] ${message}`, attrs);
        },
        callDuringReplay: false,  // Don't log during replay
      },
      error: {
        fn(workflowInfo, message, attrs) {
          console.error(`[${workflowInfo.workflowId}] ${message}`, attrs);
        },
        callDuringReplay: false,
      },
    },
  },
});
```

SHA-256: a4433dfcd6df2cd26f877ebe3f3b9deba5fe7e6931b5e995d7045843ec06b760