Skip to content

Appstream-Studio/durable-patterns

Repository files navigation

AppStream Studio

License NuGet Package Build Status

Durable Patterns

Welcome to the Durable Patterns Library!

Our library is here to help you make better use of Azure Durable Functions Framework without unnecessary boilerplate code. It provides fluent interface for orchestrator function to easily build efficient and scalable processes that implements the typical application patterns like:

  • fan out / fan in
  • function chaining
  • Monitoring pattern

You just inject business logic enclosed in IPatternActivity implementations and our library will take care of creating activity functions, passing the arguments and injecting objects without the need to write repeatable sections.

Get Started with Durable Patterns

Durable Patterns can be installed using the Nuget package manager or the dotnet CLI.

dotnet add package AppStream.DurablePatterns

To use this library you need to instruct durable functions framework to look for activity functions not only in your startup project by adding this property in of your startup project's csproj:

<FunctionsInDependencies>true</FunctionsInDependencies>

Example - fan out / fan in

Program.cs

using AppStream.DurablePatterns;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services => services.AddDurablePatterns(cfg => cfg.AddActivitiesFromAssembly(typeof(GetItems).Assembly))
    .Build();

host.Run();

IPatternActivity classes

using AppStream.DurablePatterns;

internal class GetItems : IPatternActivity<List<Item>>
{
    private readonly IRepository _repository;

    public GetItems(IRepository repository)
    {
        _repository = repository;
    }

    public async Task<PatternActivityResult<List<Item>>> RunAsync(object? input)
    {
        return new PatternActivityResult<List<Item>>(
            value: await _repository.GetItemsAsync(),
            output: new { whateverYouWantToBeDisplayedInOrchestratorOutput = true });
    }
}

internal class FanOut : IPatternActivity<List<Item>, List<Item>>
{
    private readonly IItemProcessingService _service;

    public FanOut(IItemProcessingService service)
    {
        _service = service;
    }

    public Task<PatternActivityResult<List<Item>>> RunAsync(List<Item> input)
    {
        // this block of code will be executed in parallel batches
        var processedItems = new List<Item>();

        foreach (var item in input)
        {
            processedItems.Add(_service.Process(item));
        }

        return Task.FromResult(new PatternActivityResult<List<Item>>(processedItems, new { foo = "bar" }));
    }
}

internal class FanIn : IPatternActivity<List<Item>, List<Item>>
{
    private readonly IOtherItemProcessingService _service;

    public FanIn(IOtherItemProcessingService service)
    {
        _service = service;
    }

    public Task<PatternActivityResult<List<Item>>> RunAsync(List<Item> input)
    {
        // this block of code will be executed once and the input will be all items returned from all FanOut activities
        var processedItems = new List<Item>();

        foreach (var item in input)
        {
            processedItems.Add(_service.Process(item));
        }

        return Task.FromResult(new PatternActivityResult<List<Item>>(processedItems, new { foo = "bar" }));
    }
}

Orchestrator function

using AppStream.DurablePatterns;

internal class MyOrchestrator
{
    private readonly IDurablePatterns _patterns;

    public MyOrchestrator(
        IDurablePatterns patterns)
    {
        _patterns = patterns;
    }

    [Function("Orchestrator")]
    public Task<ExecutionResult> RunOrchestrator(
        [OrchestrationTrigger] TaskOrchestrationContext context)
    {
        return _patterns
            .WithContext(context)
            .RunActivity<GetItems>()
            .FanOutFanIn<FanOut>(new FanOutFanInOptions(BatchSize: 2, ParallelActivityFunctionsCap: 2))
            .RunActivity<FanIn>()
            .ExecuteAsync();
    }
}

Roadmap

  • Updating orchestration status during execution
  • Support for lambdas instead of explicit IPatternActivity implementations
  • Naming the activities for easier debugging
  • Add support for Monitoring pattern
  • Add support for Human interaction pattern

Contributing

Contributions to this open source library are highly appreciated! If you're interested in helping out, please feel free to submit a pull request with your changes. We welcome contributions of all kinds, whether it's bug fixes, new features, or just improving the documentation. Please ensure that your code is well-documented, tested, and adheres to the coding conventions used in the project. Don't hesitate to reach out if you have any questions or need help getting started. You can open an issue on GitHub or email us at [email protected] - we're happy to assist you in any way we can.

About

Library simplifying usage of most common durable functions patterns

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages