Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
86 changes: 86 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copilot Instructions for durabletask-python

## Project Overview

This is the Durable Task Python SDK, providing a client and worker for
building durable orchestrations. The repo contains two packages:

- `durabletask` — core SDK (in `durabletask/`)
- `durabletask.azuremanaged` — Azure Durable Task Scheduler provider (in `durabletask-azuremanaged/`)

## Language and Style

- Python 3.10+ is required.
- Use type hints for all public API signatures.
- Follow PEP 8 conventions.
- Use `autopep8` for Python formatting.

## Markdown Style

Use GitHub-style callouts for notes, warnings, and tips in Markdown files:

```markdown
> [!NOTE]
> This is a note.

> [!WARNING]
> This is a warning.

> [!TIP]
> This is a tip.
```

Do **not** use bold-text callouts like `**NOTE:**` or `> **Note:**`.

When providing shell commands in Markdown, include both Bash and
PowerShell examples if the syntax differs between them. Common cases
include multiline commands (Bash uses `\` for line continuation while
PowerShell uses a backtick `` ` ``), environment variable syntax, and
path separators. If a command is identical in both shells, a single
example is sufficient.

## Markdown Linting

This repository uses [pymarkdownlnt](https://pypi.org/project/pymarkdownlnt/)
for linting Markdown files. Configuration is in `.pymarkdown.json` at the
repository root.

To lint a single file:

```bash
pymarkdown -c .pymarkdown.json scan path/to/file.md
```

To lint all Markdown files in the repository:

```bash
pymarkdown -c .pymarkdown.json scan **/*.md
```

Install the linter via the dev dependencies:

```bash
pip install -r dev-requirements.txt
```

## Building and Testing

Install the packages locally in editable mode:

```bash
pip install -e . -e ./durabletask-azuremanaged
```

Run tests with pytest:

```bash
pytest
```

## Project Structure

- `durabletask/` — core SDK source
- `durabletask-azuremanaged/` — Azure managed provider source
- `examples/` — example orchestrations (see `examples/README.md`)
- `tests/` — test suite
- `dev-requirements.txt` — development dependencies
10 changes: 10 additions & 0 deletions .pymarkdown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"plugins": {
"md013": {
"line_length": 100
},
"md014": {
"enabled": false
}
}
}
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
grpcio-tools
pymarkdownlnt
12 changes: 11 additions & 1 deletion durabletask/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,7 @@ class _EntityExecutor:
def __init__(self, registry: _Registry, logger: logging.Logger):
self._registry = registry
self._logger = logger
self._entity_method_cache: dict[tuple[type, str], bool] = {}

def execute(
self,
Expand Down Expand Up @@ -1948,7 +1949,16 @@ def execute(
raise TypeError(f"Entity operation '{operation}' is not callable")
# Execute the entity method
entity_instance._initialize_entity_context(ctx)
entity_output = method(entity_input)
cache_key = (type(entity_instance), operation)
expects_input = self._entity_method_cache.get(cache_key)
if expects_input is None:
sig = inspect.signature(method)
expects_input = len(sig.parameters) > 0
self._entity_method_cache[cache_key] = expects_input
if expects_input:
entity_output = method(entity_input)
else:
entity_output = method()
else:
# Execute the entity function
entity_output = fn(ctx, entity_input)
Expand Down
192 changes: 141 additions & 51 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,86 +1,176 @@
# Examples

This directory contains examples of how to author durable orchestrations using the Durable Task Python SDK in conjunction with the Durable Task Scheduler (DTS).
This directory contains examples of how to author durable orchestrations
using the Durable Task Python SDK in conjunction with the
Durable Task Scheduler (DTS).

## Prerequisites

If using a deployed Durable Task Scheduler:
- [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli)
- [`az durabletask` CLI extension](https://learn.microsoft.com/en-us/cli/azure/durabletask?view=azure-cli-latest)

- [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli)
- [`az durabletask` CLI extension](https://learn.microsoft.com/cli/azure/durabletask?view=azure-cli-latest)

## Running the Examples

There are two separate ways to run an example:

- Using the Emulator (recommended for learning and development)
- Using a deployed Scheduler and Taskhub in Azure
- Using a deployed Scheduler and Taskhub in Azure

### Running with the Emulator
We recommend using the emulator for learning and development as it's faster to set up and doesn't require any Azure resources. The emulator simulates a scheduler and taskhub, packaged into an easy-to-use Docker container.

We recommend using the emulator for learning and development as it's
faster to set up and doesn't require any Azure resources. The emulator
simulates a scheduler and taskhub, packaged into an easy-to-use
Docker container.

1. Install Docker: If it is not already installed.

2. Pull the Docker Image for the Emulator:
```bash
docker pull mcr.microsoft.com/dts/dts-emulator:v0.0.6
```
1. Pull the Docker Image for the Emulator:

3. Run the Emulator: Wait a few seconds for the container to be ready.
```bash
docker run --name dtsemulator -d -p 8080:8080 mcr.microsoft.com/dts/dts-emulator:v0.0.6
```
```bash
docker pull mcr.microsoft.com/dts/dts-emulator:latest
```

4. Install the Required Packages:
```bash
pip install -r requirements.txt
```
1. Run the Emulator: Wait a few seconds for the container to be ready.

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

1. Create a Python virtual environment (recommended):

```bash
python -m venv .venv
```

Note: The example code has been updated to use the default emulator settings automatically (endpoint: http://localhost:8080, taskhub: default). You don't need to set any environment variables.
Activate the virtual environment:

Bash:

```bash
source .venv/bin/activate
```

PowerShell:

```powershell
.\.venv\Scripts\Activate.ps1
```

1. Install the Required Packages:

```bash
pip install -r requirements.txt
```

If you are running from a local clone of the repository, install the
local packages in editable mode instead (run this from the repository
root, not the `examples/` directory):

```bash
pip install -e . -e ./durabletask-azuremanaged
```

> [!NOTE]
> The example code uses the default emulator settings
> automatically (endpoint: `http://localhost:8080`, taskhub: `default`).
> You don't need to set any environment variables.

### Running with a Deployed Scheduler and Taskhub Resource in Azure
For production scenarios or when you're ready to deploy to Azure, you can create a taskhub using the Azure CLI:

For production scenarios or when you're ready to deploy to Azure, you
can create a taskhub using the Azure CLI:

1. Create a Scheduler:
```bash
az durabletask scheduler create --resource-group <testrg> --name <testscheduler> --location <eastus> --ip-allowlist "[0.0.0.0/0]" --sku-capacity 1 --sku-name "Dedicated" --tags "{'myattribute':'myvalue'}"
```

2. Create Your Taskhub:
```bash
az durabletask taskhub create --resource-group <testrg> --scheduler-name <testscheduler> --name <testtaskhub>
```
Bash:

3. Retrieve the Endpoint for the Scheduler: Locate the taskhub in the Azure portal to find the endpoint.
```bash
az durabletask scheduler create \
--resource-group <testrg> \
--name <testscheduler> \
--location <eastus> \
--ip-allowlist "[0.0.0.0/0]" \
--sku-capacity 1 \
--sku-name "Dedicated" \
--tags "{'myattribute':'myvalue'}"
```

4. Set the Environment Variables:
Bash:
```bash
export TASKHUB=<taskhubname>
export ENDPOINT=<taskhubEndpoint>
```
Powershell:
```powershell
$env:TASKHUB = "<taskhubname>"
$env:ENDPOINT = "<taskhubEndpoint>"
```
PowerShell:

5. Install the Required Packages:
```bash
pip install -r requirements.txt
```
```powershell
az durabletask scheduler create `
--resource-group <testrg> `
--name <testscheduler> `
--location <eastus> `
--ip-allowlist "[0.0.0.0/0]" `
--sku-capacity 1 `
--sku-name "Dedicated" `
--tags "{'myattribute':'myvalue'}"
```

1. Create Your Taskhub:

Bash:

```bash
az durabletask taskhub create \
--resource-group <testrg> \
--scheduler-name <testscheduler> \
--name <testtaskhub>
```

PowerShell:

```powershell
az durabletask taskhub create `
--resource-group <testrg> `
--scheduler-name <testscheduler> `
--name <testtaskhub>
```

1. Retrieve the Endpoint for the Scheduler: Locate the taskhub in the
Azure portal to find the endpoint.

1. Set the Environment Variables:

Bash:

```bash
export TASKHUB=<taskhubname>
export ENDPOINT=<taskhubEndpoint>
```

PowerShell:

```powershell
$env:TASKHUB = "<taskhubname>"
$env:ENDPOINT = "<taskhubEndpoint>"
```

1. Install the Required Packages:

```bash
pip install -r requirements.txt
```

### Executing the Examples

### Running the Examples
You can now execute any of the examples in this directory using Python:

```bash
python3 example_file.py
python activity_sequence.py
```

### Review Orchestration History and Status in the Durable Task Scheduler Dashboard
To access the Durable Task Scheduler Dashboard, follow these steps:
### Review Orchestration History and Status

- **Using the Emulator**: By default, the dashboard runs on portal 8082. Navigate to http://localhost:8082 and click on the default task hub.
To access the Durable Task Scheduler Dashboard, follow these steps:

- **Using a Deployed Scheduler**: Navigate to the Scheduler resource. Then, go to the Task Hub subresource that you are using and click on the dashboard URL in the top right corner.
- **Using the Emulator**: By default, the dashboard runs on port 8082.
Navigate to <http://localhost:8082> and click on the default task hub.

```sh
python3 activity_sequence.py
```
- **Using a Deployed Scheduler**: Navigate to the Scheduler resource.
Then, go to the Task Hub subresource that you are using and click on
the dashboard URL in the top right corner.
6 changes: 2 additions & 4 deletions examples/activity_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ def sequence(ctx: task.OrchestrationContext, _):
print(f"Using endpoint: {endpoint}")

# Set credential to None for emulator, or DefaultAzureCredential for Azure
credential = None if endpoint == "http://localhost:8080" else DefaultAzureCredential()

# configure and start the worker - use secure_channel=False for emulator
secure_channel = endpoint != "http://localhost:8080"
secure_channel = endpoint.startswith("https://")
credential = DefaultAzureCredential() if secure_channel else None
with DurableTaskSchedulerWorker(host_address=endpoint, secure_channel=secure_channel,
taskhub=taskhub_name, token_credential=credential) as w:
w.add_orchestrator(sequence)
Expand Down
8 changes: 3 additions & 5 deletions examples/entities/class_based_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def set(self, input: int):

def add(self, input: int):
current_state = self.get_state(int, 0)
new_state = current_state + (input or 1)
new_state = current_state + (1 if input is None else input)
self.set_state(new_state)
return new_state

Expand Down Expand Up @@ -44,10 +44,8 @@ def counter_orchestrator(ctx: task.OrchestrationContext, _):
print(f"Using endpoint: {endpoint}")

# Set credential to None for emulator, or DefaultAzureCredential for Azure
credential = None if endpoint == "http://localhost:8080" else DefaultAzureCredential()

# configure and start the worker - use secure_channel=False for emulator
secure_channel = endpoint != "http://localhost:8080"
secure_channel = endpoint.startswith("https://")
credential = DefaultAzureCredential() if secure_channel else None
with DurableTaskSchedulerWorker(host_address=endpoint, secure_channel=secure_channel,
taskhub=taskhub_name, token_credential=credential) as w:
w.add_orchestrator(counter_orchestrator)
Expand Down
Loading
Loading