Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This workflow generates weekly CodeQL reports for this repo, a security requirements.
# This workflow generates weekly CodeQL reports for this repo, a security requirement.
# The workflow is adapted from the following reference: https://github.com/Azure-Samples/azure-functions-python-stream-openai/pull/2/files
# Generic comments on how to modify these file are left intactfor future maintenance.
# Generic comments on how to modify this file are left intact for future maintenance.

name: "CodeQL"

Expand Down Expand Up @@ -30,7 +30,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ['typescript']
language: ['javascript']
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

Expand Down Expand Up @@ -62,5 +62,3 @@ jobs:
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

category: "/language:${{matrix.language}}"
8 changes: 4 additions & 4 deletions examples/azure-managed-dts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,23 @@ import { Task } from "../src/task/task";
// These values should be set as environment variables
const endpoint = process.env.AZURE_DTS_ENDPOINT;
const taskHubName = process.env.AZURE_DTS_TASKHUB;
const connectionString = process.env.AZURE_DTS_CONNECTION_STRING;
const connectionString = process.env.DURABLE_TASK_SCHEDULER_CONNECTION_STRING;

// Validate configuration
if (!connectionString && (!endpoint || !taskHubName)) {
logger.error(
"Error: Either AZURE_DTS_CONNECTION_STRING or both AZURE_DTS_ENDPOINT and AZURE_DTS_TASKHUB must be set.",
"Error: Either DURABLE_TASK_SCHEDULER_CONNECTION_STRING or both AZURE_DTS_ENDPOINT and AZURE_DTS_TASKHUB must be set.",
);
logger.info("\nUsage:");
logger.info(" Option 1: Create a .env file in the examples directory (recommended):");
logger.info(
" AZURE_DTS_CONNECTION_STRING=Endpoint=https://myservice.durabletask.io;Authentication=DefaultAzure;TaskHub=myTaskHub",
" DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=https://myservice.durabletask.io;Authentication=DefaultAzure;TaskHub=myTaskHub",
);
logger.info(" or");
logger.info(" AZURE_DTS_ENDPOINT=https://myservice.durabletask.io");
logger.info(" AZURE_DTS_TASKHUB=myTaskHub");
logger.info("\n Option 2: Set environment variables directly");
logger.info(" export AZURE_DTS_CONNECTION_STRING=...");
logger.info(" export DURABLE_TASK_SCHEDULER_CONNECTION_STRING=...");
process.exit(1);
}

Expand Down
8 changes: 8 additions & 0 deletions examples/azure-managed/.env.emulator
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Configuration for running with the local DTS Emulator + Jaeger
# Copy this file to .env: cp .env.emulator .env

# DTS Emulator connection string (no authentication required)
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=http://localhost:8080;Authentication=None;TaskHub=default

# OTLP endpoint for trace export (Jaeger's OTLP HTTP receiver)
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
4 changes: 2 additions & 2 deletions examples/azure-managed/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Option 1: Using connection string (recommended)
# Supported authentication types: DefaultAzure, ManagedIdentity, WorkloadIdentity,
# Environment, AzureCli, AzurePowerShell, VisualStudioCode, InteractiveBrowser, None
AZURE_DTS_CONNECTION_STRING=Endpoint=https://your-scheduler.eastus.durabletask.io;Authentication=DefaultAzure;TaskHub=your-taskhub
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=https://your-scheduler.eastus.durabletask.io;Authentication=DefaultAzure;TaskHub=your-taskhub
# Option 2: Using explicit parameters (uses DefaultAzureCredential)
# Uncomment these lines and comment out AZURE_DTS_CONNECTION_STRING above
# Uncomment these lines and comment out DURABLE_TASK_SCHEDULER_CONNECTION_STRING above
# AZURE_DTS_ENDPOINT=https://your-scheduler.eastus.durabletask.io
# AZURE_DTS_TASKHUB=your-taskhub
252 changes: 252 additions & 0 deletions examples/azure-managed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
# Distributed Tracing with Azure Managed Durable Task Scheduler

This example demonstrates **OpenTelemetry distributed tracing** with the Durable Task JavaScript SDK and Azure Managed Durable Task Scheduler (DTS). Traces are exported to [Jaeger](https://www.jaegertracing.io/) so you can visualize the full orchestration lifecycle as connected spans.

## What You'll See

When you run this example, the SDK automatically produces [W3C Trace Context](https://www.w3.org/TR/trace-context/) spans for every stage of a durable orchestration:

| Span | Kind | Description |
|------|------|-------------|
| `create_orchestration:<name>` | PRODUCER | Client scheduling a new orchestration |
| `orchestration:<name>` | SERVER | Worker executing the orchestration |
| `activity:<name>` (scheduling) | CLIENT | Orchestrator scheduling an activity |
| `activity:<name>` (execution) | SERVER | Worker executing the activity |
| `timer:<orchestrationName>` | INTERNAL | Timer created inside an orchestration |
| `orchestration_event:<eventName>` | PRODUCER | Event raised to another orchestration |

All spans are linked via `traceparent` propagation, giving you a single end-to-end trace from the client all the way through parallel activity fan-out and back.

### Sample Trace in Jaeger

```
create_orchestration:dataPipelineOrchestrator (PRODUCER)
└─ orchestration:dataPipelineOrchestrator (SERVER)
├─ activity:getDataSources (CLIENT → SERVER)
├─ activity:fetchData ×4 (CLIENT → SERVER, parallel)
├─ activity:transformData ×4 (CLIENT → SERVER, parallel)
└─ activity:saveResults (CLIENT → SERVER)
```

---

## Prerequisites

- **Node.js ≥ 22** (required by the monorepo)
- **Docker** (for the DTS Emulator and Jaeger)
- **npm** (for installing dependencies)

---

## Quick Start (Local with DTS Emulator)

### 1. Start the DTS Emulator and Jaeger

A `docker-compose.yml` is provided that starts both services:

```bash
cd examples/azure-managed
docker compose up -d
```

This starts:

| Service | Port | Purpose |
|---------|------|---------|
| **DTS Emulator** | `8080` | Local gRPC endpoint (no authentication) |
| **Jaeger UI** | `16686` | Trace visualization dashboard |
| **Jaeger OTLP (HTTP)** | `4318` | OpenTelemetry trace receiver |
| **Jaeger OTLP (gRPC)** | `4317` | OpenTelemetry trace receiver (gRPC) |

> **Tip:** You can also run just the DTS Emulator standalone:
> ```bash
> docker run -d --name dts-emulator -p 8080:8080 -p 8082:8082 \
> mcr.microsoft.com/dts/dts-emulator:latest
> ```

### 2. Configure Environment Variables

Copy the provided emulator configuration:

```bash
cp .env.emulator .env
```

This sets:

```env
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=http://localhost:8080;Authentication=None;TaskHub=default
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
```

### 3. Install OpenTelemetry Dependencies

From the **repository root**, install the required OTel packages:

```bash
npm install --no-save \
@opentelemetry/api \
@opentelemetry/sdk-node \
@opentelemetry/sdk-trace-base \
@opentelemetry/exporter-trace-otlp-http \
@opentelemetry/resources \
@opentelemetry/semantic-conventions
```

> **Note:** `@opentelemetry/api` is an optional peer dependency of `@microsoft/durabletask-js`. When it's installed, the SDK automatically produces distributed tracing spans — no code changes needed in your orchestrations or activities.

### 4. Build the SDK (if not already built)

```bash
npm run build
```

### 5. Run the Example

```bash
npm run example -- ./examples/azure-managed/distributed-tracing.ts
```

You should see output like:

```
OpenTelemetry SDK started – exporting traces to http://localhost:4318

=== Sequence Orchestration ===
Scheduled: abc123
Completed – result: ["Hello, Tokyo!","Hello, Seattle!","Hello, London!"]

=== Data Pipeline Orchestration ===
Scheduled: def456
Completed – result: {"sourcesProcessed":4,"resultsSaved":4,"data":["transformed(data-from-users-api)",...]}

=== All orchestrations completed! ===
Open Jaeger UI at http://localhost:16686 and search for service "durabletask-js-tracing-example" to view traces.
```

### 6. View Traces in Jaeger

1. Open [http://localhost:16686](http://localhost:16686) in your browser.
2. Select the service **`durabletask-js-tracing-example`** from the dropdown.
3. Click **Find Traces**.
4. Click on a trace to explore the span waterfall.

---

## Running Against Azure Managed DTS (Cloud)

To run this example against a real Azure Managed Durable Task Scheduler endpoint instead of the local emulator:

### 1. Create a `.env` file

```env
# Option A: Connection string
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=https://your-scheduler.eastus.durabletask.io;Authentication=DefaultAzure;TaskHub=your-taskhub

# Option B: Explicit parameters (uses DefaultAzureCredential)
# AZURE_DTS_ENDPOINT=https://your-scheduler.eastus.durabletask.io
# AZURE_DTS_TASKHUB=your-taskhub

# OTLP endpoint (Jaeger, Azure Monitor, Aspire Dashboard, etc.)
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
```

### 2. Authenticate

Make sure you're logged in via Azure CLI:

```bash
az login
```

### 3. Run

```bash
npm run example -- ./examples/azure-managed/distributed-tracing.ts
```

---

## Using Azure Monitor / Application Insights

To export traces to **Azure Monitor** instead of Jaeger, replace the OTLP exporter with the Azure Monitor exporter:

```bash
npm install --no-save @azure/monitor-opentelemetry-exporter
```

Then modify the OpenTelemetry setup in `distributed-tracing.ts`:

```typescript
import { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";

const traceExporter = new AzureMonitorTraceExporter({
connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,
});
```

---

## DTS Emulator Docker Image Reference

| Property | Value |
|----------|-------|
| **Image** | `mcr.microsoft.com/dts/emulator:latest` |
| **gRPC Port** | `8080` |
| **Dashboard Port** | `8082` |
| **Authentication** | `None` (no credentials required) |
| **Connection String** | `Endpoint=http://localhost:8080;Authentication=None;TaskHub=default` |

### Running the Emulator Standalone

```bash
docker run -d \
--name dts-emulator \
-p 8080:8080 \
-p 8082:8082 \
mcr.microsoft.com/dts/emulator:latest
```

### Stopping the Emulator

```bash
docker stop dts-emulator && docker rm dts-emulator
```

---

## How Distributed Tracing Works

The Durable Task JavaScript SDK uses OpenTelemetry as an **optional peer dependency**. When `@opentelemetry/api` is installed and a `TracerProvider` is registered, the SDK automatically:

1. **Creates spans** for orchestration scheduling, execution, activity scheduling/execution, timers, and events.
2. **Propagates W3C `traceparent`** through the gRPC protocol so that spans from the client, orchestrator, and activities are all linked in a single trace.
3. **Handles replay correctly** – on orchestration replay, the SDK carries forward the original span ID so all replay iterations correlate to the same logical orchestration execution.

The tracer is registered under the name **`Microsoft.DurableTask`**, and spans include semantic attributes like:

- `durabletask.type` – `orchestration`, `activity`, `timer`, `event`, etc.
- `durabletask.task.name` – The function name.
- `durabletask.task.instance_id` – The orchestration instance ID.
- `durabletask.task.task_id` – The sequential task ID within an orchestration.

---

## Cleanup

```bash
cd examples/azure-managed
docker compose down
```

---

## Files in This Example

| File | Description |
|------|-------------|
| `distributed-tracing.ts` | Main example – OTel setup + orchestrations |
| `docker-compose.yml` | DTS Emulator + Jaeger stack |
| `.env.emulator` | Pre-configured env vars for the local emulator |
| `.env.example` | Template for Azure Managed DTS (cloud) |
| `index.ts` | Basic example (no tracing) |
Loading
Loading