Блок Transform Block, связывающий несколько целей с предикатом, который не работает должным образом - PullRequest
0 голосов
/ 09 июля 2019

У меня есть блок преобразования, который связан с блоком действия на основе предиката.

// Blocks
public TransformBlock<Document, Document> DocumentCreationTransformBlock =
    new TransformBlock<Document, Document>(async document => 
    {          
        return await CreateAsync(document); // REST API call that sets document.NewId
    }, 
    new ExecutionDataflowBlockOptions {
        BoundedCapacity = 100,
        MaxDegreeOfParallelism = 20
    });

public ActionBlock<Document> SplitPipelineActionBlock = 
    new ActionBlock<Document>(async document => 
    { // implementation obfuscated 
    },
    new ExecutionDataflowBlockOptions {
        BoundedCapacity = 100           
    }; 

// Shared block elements      
public DataflowLinkOptions CommonLinkOptions = new DataflowLinkOptions {
    PropagateCompletion = true };

// Link mesh
DocumentCreationTransformBlock.LinkTo(SplitPipelineActionBlock, 
    CommonLinkOptions, 
    document => !string.IsNullOrEmpty(document.NewId));

DocumentCreationTransformBlock.LinkTo(DataflowBlock.NullTarget<Document>(), 
    CommonLinkOptions);

Блок преобразования пытается создать документ с помощью API REST.Он должен обновить объект Document на NewId.Таким образом, предикат LinkTo проверяет, что возвращаемый документ имеет NewId.

Для любых объектов, не соответствующих этому критерию, существует блок NullTarget для очистки TransformBlock.

В моем тесте я отправил 10 100 пунктов в конвейер и подтвердил, что все элементы вернули NewId успешно.Тем не менее, 130 предметов передаются в NullTarget.Когда я снова запускаю программу по всему набору, более 3000 элементов передаются в NullTarget.Даже предметы, которые ранее успешно хранились NewId.

Я подозреваю, что существует проблема с заполнением SplitPipelineActionBlock BoundedCapacity, а LinkTo просто игнорирует предикат и затем передает элемент для обработки следующим LinkTo, то есть NullTarget.

Как сделать так, чтобы все предметы имели возможность быть отправленными в блок SplitPipeLineAction?

1 Ответ

3 голосов
/ 09 июля 2019

Когда элемент доступен из исходного блока, он будет предлагать его своим ссылкам по одному;если какая-либо ссылка не получает элемент, то этот элемент предлагается для следующей ссылки.Нет никакого отличительного , почему ссылка не используется.Блоки действительно отличают ответы «возможно позже» от ответов «нет» (Postponed против Declined), но в любом случае будет предпринята попытка следующей ссылки для связанного блока, который может принять его now .

Лучшим вариантом решения этой проблемы является добавление предиката к нулевой ссылке блока, которая является отрицательной по отношению к предикату для целевой ссылки блока.

Predicate<Document> predicate = document => !string.IsNullOrEmpty(document.NewId);

DocumentCreationTransformBlock.LinkTo(SplitPipelineActionBlock, 
    CommonLinkOptions, 
    predicate);

DocumentCreationTransformBlock.LinkTo(DataflowBlock.NullTarget<Document>(), 
    CommonLinkOptions,
    document => !predicate(document));

Таким образом, когда SplitPipelineActionBlock заполнен, то элемент предлагается пустой ссылке, он отклоняется из-за сбоя предиката, и элемент остается в выходном буфере блока преобразования, пока SplitPipelineActionBlock не освободит место.

...