Skip to content
Draft
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
9 changes: 8 additions & 1 deletion DurableTask.Netherite.sln
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokenCredentialDF", "sample
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokenCredentialDTFx", "samples\TokenCredentialDTFx\TokenCredentialDTFx.csproj", "{FBFF0814-E6C0-489A-ACCF-9D0699219621}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Functions.Worker.Extensions.DurableTask.Netherite", "src\Functions.Worker.Extensions.DurableTask.Netherite\Functions.Worker.Extensions.DurableTask.Netherite.csproj", "{3E17402B-3F65-4E5B-B752-48AD56B81208}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Functions.Worker.Extensions.DurableTask.Netherite", "src\Functions.Worker.Extensions.DurableTask.Netherite\Functions.Worker.Extensions.DurableTask.Netherite.csproj", "{3E17402B-3F65-4E5B-B752-48AD56B81208}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneClient", "samples\StandaloneClient\StandaloneClient.csproj", "{CC543A91-1815-4192-88EB-89C892652ACB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -97,6 +99,10 @@ Global
{3E17402B-3F65-4E5B-B752-48AD56B81208}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E17402B-3F65-4E5B-B752-48AD56B81208}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E17402B-3F65-4E5B-B752-48AD56B81208}.Release|Any CPU.Build.0 = Release|Any CPU
{CC543A91-1815-4192-88EB-89C892652ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC543A91-1815-4192-88EB-89C892652ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC543A91-1815-4192-88EB-89C892652ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC543A91-1815-4192-88EB-89C892652ACB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -114,6 +120,7 @@ Global
{B99AB043-47DC-467C-93CB-D6C69D3B1AD4} = {AB958467-9236-402E-833C-B8DE4841AB9F}
{FBFF0814-E6C0-489A-ACCF-9D0699219621} = {AB958467-9236-402E-833C-B8DE4841AB9F}
{3E17402B-3F65-4E5B-B752-48AD56B81208} = {D33AB157-04B9-4BAD-B580-C3C87C17828C}
{CC543A91-1815-4192-88EB-89C892652ACB} = {AB958467-9236-402E-833C-B8DE4841AB9F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {238A9613-5411-41CF-BDEC-168CCD5C03FB}
Expand Down
90 changes: 90 additions & 0 deletions samples/StandaloneClient/FunctionsStartup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

// Reference: https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection
[assembly: Microsoft.Azure.Functions.Extensions.DependencyInjection.FunctionsStartup(typeof(StandaloneClient.Startup))]
namespace StandaloneClient
{
using System;
using System.Collections.Generic;
using Azure.Identity;
using DurableTask.Netherite;
using DurableTask.Netherite.AzureFunctions;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask.ContextImplementations;
using Microsoft.Azure.WebJobs.Extensions.DurableTask.Options;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Linq;
using Castle.Core.Logging;

public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<ExternalClientFactory>();
}

public class ExternalClientFactory
{
readonly DurableClientFactory configuredClientFactory;
readonly string defaultHubName;
readonly string defaultConnectionName;
readonly bool isEmulation;

const string DefaultStorageProviderName = "AzureStorage";
const string DefaultStorageConnectionName = "AzureWebJobsStorage";

public ExternalClientFactory(
IOptions<DurableClientOptions> durableClientOptions,
IOptions<DurableTaskOptions> durableTaskOptions,
Microsoft.Extensions.Logging.ILoggerFactory loggerFactory,
IServiceProvider serviceProvider)
{
// determine the name of the configured storage provider
bool storageTypeIsConfigured = durableTaskOptions.Value.StorageProvider.TryGetValue("type", out object storageType);
string storageProviderName = "AzureStorage"; // default storage provider name
if (storageTypeIsConfigured)
{
storageProviderName = storageType.ToString();
}

// find the provider factory for the configured storage provider
IEnumerable<IDurabilityProviderFactory> providerFactories = serviceProvider.GetServices<IDurabilityProviderFactory>();
IDurabilityProviderFactory providerFactory = providerFactories.First(f => string.Equals(f.Name, storageProviderName, StringComparison.OrdinalIgnoreCase));

// create the client factory
this.configuredClientFactory = new DurableClientFactory(durableClientOptions, durableTaskOptions, providerFactory, loggerFactory);

// determine the default hub name based on the configuration
this.defaultHubName = durableTaskOptions.Value.HubName;

// determine the default connection name based on the configuration
if (durableTaskOptions.Value.StorageProvider.TryGetValue("StorageConnectionName", out object value))
{
this.defaultConnectionName = value.ToString();
}
else
{
this.defaultConnectionName = DefaultStorageConnectionName;
}
}

public IDurableClient GetClient(string connectionName = null, string hubName = null)
{
var clientOptions = new DurableClientOptions() {
ConnectionName = connectionName ?? this.defaultConnectionName,
TaskHub = hubName ?? this.defaultHubName,
IsExternalClient = true,
};

var client = this.configuredClientFactory.CreateClient(clientOptions);
return client;
}
}
}
}
9 changes: 9 additions & 0 deletions samples/StandaloneClient/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"profiles": {
"ExternalClient": {
"commandName": "Project",
"commandLineArgs": "--port 7135",
"launchBrowser": false
}
}
}
17 changes: 17 additions & 0 deletions samples/StandaloneClient/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Standalone DF client

This sample demonstrates how to create a standalone durable client.

This client is constructed in a function app that is separate from the function app that runs the task hub.

It is meant to be used in conjunction with the HelloDF sample which defines the orchestration that is being executed.

## How to run it

1. Set the environment variable EventHubsConnection to contain a connection string for an event hubs namespace. You cannot use emulation for creating a standalone client.

2. Start the HelloDF sample app so it runs the task hub. Keep this running (and watch for error messages in the log).

3. In a second window, start this app (StandaloneDFClient). Keep it running (and watch for error messages in the log).

4. Issue an HTTP request to the standalone client, like `curl http://localhost:7135/test`. You should receive (possibly after a few seconds) a return message saying 'client successfully started the instance'.
20 changes: 20 additions & 0 deletions samples/StandaloneClient/StandaloneClient.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.3" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.DurableTask.Netherite.AzureFunctions" Version="1.3.0" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
44 changes: 44 additions & 0 deletions samples/StandaloneClient/Test.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace StandaloneClient
{
using System;
using System.Threading.Tasks;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.DurableTask.ContextImplementations;
using Microsoft.Azure.WebJobs.Extensions.DurableTask.Options;
using static StandaloneClient.Startup;

public class Test
{
readonly ExternalClientFactory externalClientFactory;

public Test(ExternalClientFactory externalClientFactory)
{
this.externalClientFactory = externalClientFactory;
}

[FunctionName(nameof(Test))]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
{
try
{
var client = this.externalClientFactory.GetClient();
string orchestrationInstanceId = await client.StartNewAsync("HelloSequence");
return new OkObjectResult($"client successfully started the instance {orchestrationInstanceId}.\n");
}
catch (Exception e)
{
return new ObjectResult($"exception: {e}") { StatusCode = (int)HttpStatusCode.InternalServerError };
}
}
}
}
14 changes: 14 additions & 0 deletions samples/StandaloneClient/host.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": "2.0",
"extensions": {
"http": {
"routePrefix": ""
},
"durableTask": {
"hubName": "hello",
"storageProvider": {
"type": "Netherite"
}
}
}
}
7 changes: 7 additions & 0 deletions samples/StandaloneClient/local.settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}