question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Throttling concurrent activities programmatically

See original GitHub issue

I’m looking for a suitable pattern for throttling the number of activities that are processed concurrently. I have an orchestrator function that needs to execute a list of activities and I don’t want them all to start simultaneously but to be able to control the concurrency level through a parameter received by the function. I’m aware of the maxConcurrentActivityFunctions setting, but it operates at the host level and, as far as I know, cannot be changed programmatically.

My initial attempt was to try something similar to the code below, but it does not appear to work within an orchestrator.

    using (var throttle = new SemaphoreSlim(input.DegreeOfParallelism))
    {
        var results = input.Operations.Select(async operation =>
        {
            try
            {
                await throttle.WaitAsync();
                return context.CallActivityAsync<string>("ExecuteOperation", operation);
            }
            finally
            {
                throttle.Release();
            }
        });

        await Task.WhenAll(results);
   }

Any suggestions?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:18 (1 by maintainers)

github_iconTop GitHub Comments

12reactions
f2bocommented, Feb 1, 2019

I realized the code above did not preserve the results from each activity. I cleaned it up a bit and created an extension method that you can use it to call activities that return a TResult from an input list of objects of type T.

public async static Task<IEnumerable<TResult>> ThrottleActivities<TResult, T>(
    this DurableOrchestrationContext context,
    IEnumerable<T> activities,
    string functionName,
    int degreeOfParallelism)
{
    var runningActivities = new List<Task<TResult>>();
    foreach (var activity in activities)
    {
        var pendingOperations = runningActivities.Where(p => !p.IsCompleted);
        if (pendingOperations.Count() >= degreeOfParallelism)
        {
            await Task.WhenAny(pendingOperations);
        }

        var result = context.CallActivityAsync<TResult>(functionName, activity);
        runningActivities.Add(result);
    }

    var results = await Task.WhenAll(runningActivities);

    return results;
}

For example, to invoke activities that return strings for an input list of objects of type Operation and ensure that no more than 5 are started concurrently.

[FunctionName("ExecuteBatchJob")]
public static async Task ExecuteBatchJobAsync(
    [OrchestrationTrigger] DurableOrchestrationContext context,
    ILogger logger)
{
    var input = context.GetInput<BatchJob>();

    var results = await context.ThrottleActivities<string, Operation>(
        input.Operations,
        "ExecuteOperation",
        5);

    logger.LogDebug($"Completed all operations!");
}
2reactions
tmeniercommented, Oct 26, 2020

@cgillum Thanks for the explanation, that all makes perfect sense. I know this issue is long since closed but FWIW I think a function-level throttling feature like this would be a fantastic addition to the SDK. Thanks @f2bo for the code sample, this should work well for my scenario!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to throttle multiple asynchronous tasks?
First, abstract away from threads. Especially since your operation is asynchronous, you shouldn't be thinking about "threads" at all.
Read more >
Throttling Task Submission Rate in Java
In a web server, we can configure the maximum number of concurrent connections to the server. If more connections than this limit come...
Read more >
Throttling Task Submission Rate with ThreadPoolExecutor ...
Overall, ThreadPoolExecutor makes it easier to manage and execute a large number of concurrent tasks in Java.
Read more >
API throttling guidance - Partner app developer
Concurrent API calls may lead to high number of requests per unit time, which will also cause requests to be throttled.
Read more >
Concurrency in Azure Functions
Because multiple function invocations can run on each instance concurrently, each function needs to have a way to throttle how many concurrent ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found