Skip to content

Commit

Permalink
Update Samples (Console, Netfx, Functions) (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
jviau authored Nov 30, 2022
1 parent 33bbe4b commit 98728ff
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 106 deletions.
9 changes: 5 additions & 4 deletions samples/AzureFunctionsApp/AzureFunctionsApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.8.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="0.4.1-beta" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.10.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.0.0-rc.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.7.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.7.0" OutputItemType="Analyzer" />
<PackageReference Include="Microsoft.DurableTask.Generators" Version="1.0.0-preview.1" OutputItemType="Analyzer" />
</ItemGroup>

<ItemGroup>
Expand All @@ -23,4 +24,4 @@
</None>
</ItemGroup>

</Project>
</Project>
66 changes: 66 additions & 0 deletions samples/AzureFunctionsApp/Fib.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.DurableTask;
using Microsoft.Extensions.Logging;

namespace AzureFunctionsApp;

/// <summary>
/// An example of performing the fibonacci sequence in Durable Functions. While this is both a (naive) recursive
/// implementation of fibonacci and also not the best use of Durable, it does a good job at highlighting some patterns
/// that can be used in durable. Particularly:
/// 1. Sub orchestrations
/// 2. Orchestration flexibility - can be both a top level AND a sub orchestration
/// 3. Recursion can be performed with orchestrations!
/// 4. Control flow you are used to from regular C# programming works here as well! Particularly branching.
/// 5. Concurrency can be controlled like any other C# Task.
/// </summary>
static class Fib
{
[Function(nameof(Fib))]
public static async Task<HttpResponseData> Start(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
[DurableClient] DurableClientContext durableContext,
FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger(nameof(Fib));

int? payload = await req.ReadFromJsonAsync<int>();
string instanceId = await durableContext.Client
.ScheduleNewOrchestrationInstanceAsync(nameof(FibOrchestration), payload);
logger.LogInformation("Created new orchestration with instance ID = {instanceId}", instanceId);

return durableContext.CreateCheckStatusResponse(req, instanceId);
}

[Function(nameof(FibOrchestration))]
public static async Task<int> FibOrchestration([OrchestrationTrigger] TaskOrchestrationContext context)
{
int input = context.GetInput<int>()!;
switch (input)
{
case 0 or 1:
// The activity call is here just to demonstrate how an orchestration can mix activity and
// sub-orchestration calls
return await context.CallActivityAsync<int>(nameof(FibActivity), input);
default:
// Fan out / fan in (concurrency) is done by simply invoking multiple sub orchestrations (or activities,
// or a mix of the two) at once (without yielding), then unwrapping them both. You can also use C#
// helpers like Task.WhenAll.
Task<int> left = context.CallSubOrchestratorAsync<int>(nameof(FibOrchestration), input - 1);
Task<int> right = context.CallSubOrchestratorAsync<int>(nameof(FibOrchestration), input - 2);
return (await left) + (await right);
}
}

[Function(nameof(FibActivity))]
public static int FibActivity([ActivityTrigger] int input, FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger(nameof(FibActivity));
logger.LogInformation("Fib leaf of {input}", input);
return input;
}
}
23 changes: 11 additions & 12 deletions samples/AzureFunctionsApp/HelloCitiesTyped.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace AzureFunctionsApp.Typed;

Expand All @@ -30,9 +29,9 @@ public static async Task<HttpResponseData> StartHelloCitiesTyped(
// orchestrators that are defined in the current project. The name of the generated extension methods
// are based on the names of the orchestrator classes. Note that the source generator will *not*
// generate type-safe extension methods for non-class-based orchestrator functions.
// NOTE: This feature is in PREVIEW and requires a package reference to Microsoft.DurableTask.Generators.
string instanceId = await durableContext.Client.ScheduleNewHelloCitiesTypedInstanceAsync();
logger.LogInformation("Created new orchestration with instance ID = {instanceId}", instanceId);

return durableContext.CreateCheckStatusResponse(req, instanceId);
}
}
Expand All @@ -43,9 +42,9 @@ public static async Task<HttpResponseData> StartHelloCitiesTyped(
/// that invokes the <see cref="OnRunAsync"/> method.
/// </summary>
[DurableTask(nameof(HelloCitiesTyped))]
public class HelloCitiesTyped : TaskOrchestratorBase<string, string>
public class HelloCitiesTyped : TaskOrchestrator<string?, string>
{
protected async override Task<string?> OnRunAsync(TaskOrchestrationContext context, string? input)
public async override Task<string> RunAsync(TaskOrchestrationContext context, string? input)
{
// Source generators are used to generate the type-safe activity function
// call extension methods on the context object. The names of these generated
Expand All @@ -64,9 +63,9 @@ public class HelloCitiesTyped : TaskOrchestratorBase<string, string>
/// definition that creates an instance of this class and invokes its <see cref="OnRun"/> method.
/// </summary>
[DurableTask(nameof(SayHelloTyped))]
public class SayHelloTyped : TaskActivityBase<string, string>
public class SayHelloTyped : TaskActivity<string, string>
{
readonly ILogger? logger;
readonly ILogger logger;

/// <summary>
/// Initializes a new instance of the <see cref="SayHelloTyped"/> class.
Expand All @@ -76,15 +75,15 @@ public class SayHelloTyped : TaskActivityBase<string, string>
/// Activity class constructors support constructor-based dependency injection.
/// The injected services are provided by the function's <see cref="FunctionContext.InstanceServices"/> property.
/// </remarks>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> injected by the Azure Functions runtime.</param>
public SayHelloTyped(ILoggerFactory? loggerFactory)
/// <param name="logger">The logger injected by the Azure Functions runtime.</param>
public SayHelloTyped(ILogger<SayHelloTyped> logger)
{
this.logger = loggerFactory?.CreateLogger<SayHelloTyped>();
this.logger = logger;
}

protected override string OnRun(TaskActivityContext context, string? cityName)
public override Task<string> RunAsync(TaskActivityContext context, string cityName)
{
this.logger?.LogInformation("Saying hello to {name}", cityName);
return $"Hello, {cityName}!";
this.logger.LogInformation("Saying hello to {name}", cityName);
return Task.FromResult($"Hello, {cityName}!");
}
}
1 change: 0 additions & 1 deletion samples/AzureFunctionsApp/HelloCitiesUntyped.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.DurableTask;
Expand Down
20 changes: 9 additions & 11 deletions samples/AzureFunctionsApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace AzureFunctionsApp
{
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting;
namespace AzureFunctionsApp;

public class Program
public class Program
{
public static void Main()
{
public static void Main()
{
IHost host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.Build();
IHost host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.Build();

host.Run();
}
host.Run();
}
}
12 changes: 9 additions & 3 deletions samples/ConsoleApp/ConsoleApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.DurableTask.Client" Version="0.4.1-beta" />
<PackageReference Include="Microsoft.DurableTask.Generators" Version="0.4.1-beta" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<!-- Include these packages (and not the ProjectReferences below)
<PackageReference Include="Microsoft.DurableTask.Client.Grpc" Version="1.0.0-rc.1" />
<PackageReference Include="Microsoft.DurableTask.Worker.Grpc" Version="1.0.0-rc.1" />
-->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(SrcRoot)Worker/Grpc/Worker.Grpc.csproj" />
<ProjectReference Include="$(SrcRoot)Client/Grpc/Client.Grpc.csproj" />
</ItemGroup>

</Project>
90 changes: 61 additions & 29 deletions samples/ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,78 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Grpc;
using Microsoft.Extensions.Logging;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Converters;
using Microsoft.DurableTask.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Debug);
builder.AddSimpleConsole(options =>
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
options.SingleLine = true;
options.UseUtcTimestamp = true;
options.TimestampFormat = "yyyy-mm-ddThh:mm:ss.ffffffZ ";
});
});

DurableTaskGrpcWorker worker = DurableTaskGrpcWorker.CreateBuilder()
.AddTasks(tasks =>
{
tasks.AddOrchestrator("HelloSequence", async context =>
services.AddDurableTaskClient(builder =>
{
// Configure options for this builder. Can be omitted if no options customization is needed.
builder.Configure(opt => { });
builder.UseGrpc(); // multiple overloads available for providing gRPC information

// AddDurableTaskClient allows for multiple named clients by passing in a name as the first argument.
// When using a non-default named client, you will need to make this call below to have the
// DurableTaskClient added directly to the DI container. Otherwise IDurableTaskClientProvider must be used
// to retrieve DurableTaskClients by name from the DI container. In this case, we are using the default
// name, so the line below is NOT required as it was already called for us.
builder.RegisterDirectly();
});

services.AddDurableTaskWorker(builder =>
{
var greetings = new List<string>
// Configure options for this builder. Can be omitted if no options customization is needed.
builder.Configure(opt => { });

// Register orchestrators and activities.
builder.AddTasks(tasks =>
{
await context.CallActivityAsync<string>("SayHello", "Tokyo"),
await context.CallActivityAsync<string>("SayHello", "London"),
await context.CallActivityAsync<string>("SayHello", "Seattle"),
};
tasks.AddOrchestratorFunc("HelloSequence", async context =>
{
var greetings = new List<string>
{
await context.CallActivityAsync<string>("SayHello", "Tokyo"),
await context.CallActivityAsync<string>("SayHello", "London"),
await context.CallActivityAsync<string>("SayHello", "Seattle"),
};

return greetings;
return greetings;
});

tasks.AddActivityFunc<string, string>("SayHello", (context, city) => $"Hello {city}!");
});

builder.UseGrpc(); // multiple overloads available for providing gRPC information
});
tasks.AddActivity<string, string>("SayHello", (context, city) => $"Hello {city}!");

// Can also configure worker and client options through all the existing options config methods.
// These are equivalent to the 'builder.Configure' calls above.
services.Configure<DurableTaskWorkerOptions>(opt => { });
services.Configure<DurableTaskClientOptions>(opt => { });

// Registry can also be done via options pattern. This is equivalent to the 'builder.AddTasks' call above.
// You can use all the tools options pattern has available. For example, if you have multiple workers you could
// use ConfigureAll<DurableTaskRegistry> to add tasks to ALL workers in one go. Otherwise, you need to use
// named option configuration to register to specific workers (where the name matches the name passed to
// 'AddDurableTaskWorker(name?, builder)').
services.Configure<DurableTaskRegistry>(registry => { });

// You can configure custom data converter multiple ways. One is through worker/client options configuration.
// Alternatively, data converter will be used from the service provider if available (as a singleton) AND no
// converter was explicitly set on the options.
services.AddSingleton<DataConverter>(JsonDataConverter.Default);
})
.UseLoggerFactory(loggerFactory)
.Build();

await worker.StartAsync(timeout: TimeSpan.FromSeconds(30));
await host.StartAsync();

await using DurableTaskClient client = DurableTaskGrpcClient.Create();
await using DurableTaskClient client = host.Services.GetRequiredService<DurableTaskClient>();
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("HelloSequence");
Console.WriteLine($"Created instance: '{instanceId}'");

Expand Down
13 changes: 10 additions & 3 deletions samples/NetFxConsoleApp/NetFxConsoleApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.DurableTask.Client" Version="0.4.1-beta" />
<PackageReference Include="Microsoft.DurableTask.Generators" Version="0.4.1-beta" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<!-- Include these packages (and not the ProjectReferences below)
<PackageReference Include="Microsoft.DurableTask.Client.Grpc" Version="1.0.0-rc.1" />
<PackageReference Include="Microsoft.DurableTask.Worker.Grpc" Version="1.0.0-rc.1" />
-->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(SrcRoot)Worker/Grpc/Worker.Grpc.csproj" />
<ProjectReference Include="$(SrcRoot)Client/Grpc/Client.Grpc.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit 98728ff

Please sign in to comment.