Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

88 lines
3.2 KiB

// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Infrastructure.Tasks
{
public class PartitionedActionBlock<TInput> : ITargetBlock<TInput>
{
private readonly ITargetBlock<TInput> distributor;
private readonly ActionBlock<TInput>[] workers;
public Task Completion
{
get => Task.WhenAll(workers.Select(x => x.Completion));
}
public PartitionedActionBlock(Func<TInput, Task> action, Func<TInput, long> partitioner)
: this(action, partitioner, new ExecutionDataflowBlockOptions())
{
}
public PartitionedActionBlock(Func<TInput, Task> action, Func<TInput, long> partitioner, ExecutionDataflowBlockOptions dataflowBlockOptions)
{
Guard.NotNull(action, nameof(action));
Guard.NotNull(partitioner, nameof(partitioner));
Guard.NotNull(dataflowBlockOptions, nameof(dataflowBlockOptions));
Guard.GreaterThan(dataflowBlockOptions.MaxDegreeOfParallelism, 1, nameof(dataflowBlockOptions.MaxDegreeOfParallelism));
workers = new ActionBlock<TInput>[dataflowBlockOptions.MaxDegreeOfParallelism];
for (var i = 0; i < dataflowBlockOptions.MaxDegreeOfParallelism; i++)
{
var workerOption = SimpleMapper.Map(dataflowBlockOptions, new ExecutionDataflowBlockOptions());
workerOption.MaxDegreeOfParallelism = 1;
workerOption.MaxMessagesPerTask = DataflowBlockOptions.Unbounded;
workers[i] = new ActionBlock<TInput>(action, workerOption);
}
var distributorOption = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 1,
MaxMessagesPerTask = DataflowBlockOptions.Unbounded,
BoundedCapacity = 1
};
distributor = new ActionBlock<TInput>(x =>
{
var partition = Math.Abs(partitioner(x)) % workers.Length;
return workers[partition].SendAsync(x);
}, distributorOption);
distributor.Completion.ContinueWith(x =>
{
foreach (var worker in workers)
{
worker.Complete();
}
});
}
public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
{
return distributor.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
}
public void Complete()
{
distributor.Complete();
}
public void Fault(Exception exception)
{
distributor.Fault(exception);
}
}
}