TPL Dataflow, Exception in block fault handler does not propagate












0















I'm using a TPL dataflow block to process a stream of messages. My data flow network is composed of two blocks, a BufferBlock and an ActionBlock, with the action block being defined as:



        _actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 4,
});


If an error occurs inside the action block, I want to let the fault propagate up and exit the application. Later on I'm planning to add in logic here to handle transient errors, but for now, any errors should cause the application to exit with the fault details. To this end, I've added a ContinueWith section like this:



        _actionBlock
.Completion
.ContinueWith(dbt =>
{
var inner = dbt.Exception.InnerExceptions.First();
throw inner;
},
TaskContinuationOptions.OnlyOnFaulted
);


The problem is that the "throw inner" doesn't propagate up to anywhere, the application just carries on as if the exception was being swallowed. I don't have any further exception handlers in my code. As an experiment I've tried





  • Re-throwing the exception using



       Dispatcher.CurrentDispatcher.Invoke(() => throw ...)


  • Checking that the ContinueWith contents are running on the UI thread.



  • Handling any top level exceptions using:



    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ToplevelHandler);



(The exception thrown never reaches TopLevelHandler)



None of these has helped.



How can I make the exception that I throw inside the ContinueWith function propagate to the top of the application and make the application exit with an error message?










share|improve this question

























  • When you throw inner you'll need to await that Task at some point to propagate the exception.

    – JSteward
    Nov 20 '18 at 15:53











  • _actionBlock is long running though. I create it on application startup and under the normal course of things it keeps running for the length of the application. There's isn't a natural point in the code where I could await it's Completion task without blocking everything.

    – James
    Nov 20 '18 at 16:34











  • Unfortunately that's where the exception winds up. But in that event the ActionBlock is faulted and wouldn't continue processing anyway. You can handle exceptions within the flow or attach them to the result of the flow for handling outside.

    – JSteward
    Nov 20 '18 at 16:40











  • @James ActionBlocks are always long running. If you want to handle exceptions after the block completes, though a fault or normal completion, you await it. ContinueWith will only run when that ActionBlock completes anyway.

    – Panagiotis Kanavos
    Nov 21 '18 at 16:24











  • @James as for the exception not propagating, you wrote the equivalent of TaskFactory.StartNew(()=>throw new Exception());. If you don't await that task, the exception will disappear. Where do you want that error to appear anyway?

    – Panagiotis Kanavos
    Nov 21 '18 at 16:27
















0















I'm using a TPL dataflow block to process a stream of messages. My data flow network is composed of two blocks, a BufferBlock and an ActionBlock, with the action block being defined as:



        _actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 4,
});


If an error occurs inside the action block, I want to let the fault propagate up and exit the application. Later on I'm planning to add in logic here to handle transient errors, but for now, any errors should cause the application to exit with the fault details. To this end, I've added a ContinueWith section like this:



        _actionBlock
.Completion
.ContinueWith(dbt =>
{
var inner = dbt.Exception.InnerExceptions.First();
throw inner;
},
TaskContinuationOptions.OnlyOnFaulted
);


The problem is that the "throw inner" doesn't propagate up to anywhere, the application just carries on as if the exception was being swallowed. I don't have any further exception handlers in my code. As an experiment I've tried





  • Re-throwing the exception using



       Dispatcher.CurrentDispatcher.Invoke(() => throw ...)


  • Checking that the ContinueWith contents are running on the UI thread.



  • Handling any top level exceptions using:



    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ToplevelHandler);



(The exception thrown never reaches TopLevelHandler)



None of these has helped.



How can I make the exception that I throw inside the ContinueWith function propagate to the top of the application and make the application exit with an error message?










share|improve this question

























  • When you throw inner you'll need to await that Task at some point to propagate the exception.

    – JSteward
    Nov 20 '18 at 15:53











  • _actionBlock is long running though. I create it on application startup and under the normal course of things it keeps running for the length of the application. There's isn't a natural point in the code where I could await it's Completion task without blocking everything.

    – James
    Nov 20 '18 at 16:34











  • Unfortunately that's where the exception winds up. But in that event the ActionBlock is faulted and wouldn't continue processing anyway. You can handle exceptions within the flow or attach them to the result of the flow for handling outside.

    – JSteward
    Nov 20 '18 at 16:40











  • @James ActionBlocks are always long running. If you want to handle exceptions after the block completes, though a fault or normal completion, you await it. ContinueWith will only run when that ActionBlock completes anyway.

    – Panagiotis Kanavos
    Nov 21 '18 at 16:24











  • @James as for the exception not propagating, you wrote the equivalent of TaskFactory.StartNew(()=>throw new Exception());. If you don't await that task, the exception will disappear. Where do you want that error to appear anyway?

    – Panagiotis Kanavos
    Nov 21 '18 at 16:27














0












0








0








I'm using a TPL dataflow block to process a stream of messages. My data flow network is composed of two blocks, a BufferBlock and an ActionBlock, with the action block being defined as:



        _actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 4,
});


If an error occurs inside the action block, I want to let the fault propagate up and exit the application. Later on I'm planning to add in logic here to handle transient errors, but for now, any errors should cause the application to exit with the fault details. To this end, I've added a ContinueWith section like this:



        _actionBlock
.Completion
.ContinueWith(dbt =>
{
var inner = dbt.Exception.InnerExceptions.First();
throw inner;
},
TaskContinuationOptions.OnlyOnFaulted
);


The problem is that the "throw inner" doesn't propagate up to anywhere, the application just carries on as if the exception was being swallowed. I don't have any further exception handlers in my code. As an experiment I've tried





  • Re-throwing the exception using



       Dispatcher.CurrentDispatcher.Invoke(() => throw ...)


  • Checking that the ContinueWith contents are running on the UI thread.



  • Handling any top level exceptions using:



    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ToplevelHandler);



(The exception thrown never reaches TopLevelHandler)



None of these has helped.



How can I make the exception that I throw inside the ContinueWith function propagate to the top of the application and make the application exit with an error message?










share|improve this question
















I'm using a TPL dataflow block to process a stream of messages. My data flow network is composed of two blocks, a BufferBlock and an ActionBlock, with the action block being defined as:



        _actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 4,
});


If an error occurs inside the action block, I want to let the fault propagate up and exit the application. Later on I'm planning to add in logic here to handle transient errors, but for now, any errors should cause the application to exit with the fault details. To this end, I've added a ContinueWith section like this:



        _actionBlock
.Completion
.ContinueWith(dbt =>
{
var inner = dbt.Exception.InnerExceptions.First();
throw inner;
},
TaskContinuationOptions.OnlyOnFaulted
);


The problem is that the "throw inner" doesn't propagate up to anywhere, the application just carries on as if the exception was being swallowed. I don't have any further exception handlers in my code. As an experiment I've tried





  • Re-throwing the exception using



       Dispatcher.CurrentDispatcher.Invoke(() => throw ...)


  • Checking that the ContinueWith contents are running on the UI thread.



  • Handling any top level exceptions using:



    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ToplevelHandler);



(The exception thrown never reaches TopLevelHandler)



None of these has helped.



How can I make the exception that I throw inside the ContinueWith function propagate to the top of the application and make the application exit with an error message?







c# task-parallel-library tpl-dataflow






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 12 '18 at 8:02









Panagiotis Kanavos

55.7k483112




55.7k483112










asked Nov 20 '18 at 14:06









JamesJames

1,7401123




1,7401123













  • When you throw inner you'll need to await that Task at some point to propagate the exception.

    – JSteward
    Nov 20 '18 at 15:53











  • _actionBlock is long running though. I create it on application startup and under the normal course of things it keeps running for the length of the application. There's isn't a natural point in the code where I could await it's Completion task without blocking everything.

    – James
    Nov 20 '18 at 16:34











  • Unfortunately that's where the exception winds up. But in that event the ActionBlock is faulted and wouldn't continue processing anyway. You can handle exceptions within the flow or attach them to the result of the flow for handling outside.

    – JSteward
    Nov 20 '18 at 16:40











  • @James ActionBlocks are always long running. If you want to handle exceptions after the block completes, though a fault or normal completion, you await it. ContinueWith will only run when that ActionBlock completes anyway.

    – Panagiotis Kanavos
    Nov 21 '18 at 16:24











  • @James as for the exception not propagating, you wrote the equivalent of TaskFactory.StartNew(()=>throw new Exception());. If you don't await that task, the exception will disappear. Where do you want that error to appear anyway?

    – Panagiotis Kanavos
    Nov 21 '18 at 16:27



















  • When you throw inner you'll need to await that Task at some point to propagate the exception.

    – JSteward
    Nov 20 '18 at 15:53











  • _actionBlock is long running though. I create it on application startup and under the normal course of things it keeps running for the length of the application. There's isn't a natural point in the code where I could await it's Completion task without blocking everything.

    – James
    Nov 20 '18 at 16:34











  • Unfortunately that's where the exception winds up. But in that event the ActionBlock is faulted and wouldn't continue processing anyway. You can handle exceptions within the flow or attach them to the result of the flow for handling outside.

    – JSteward
    Nov 20 '18 at 16:40











  • @James ActionBlocks are always long running. If you want to handle exceptions after the block completes, though a fault or normal completion, you await it. ContinueWith will only run when that ActionBlock completes anyway.

    – Panagiotis Kanavos
    Nov 21 '18 at 16:24











  • @James as for the exception not propagating, you wrote the equivalent of TaskFactory.StartNew(()=>throw new Exception());. If you don't await that task, the exception will disappear. Where do you want that error to appear anyway?

    – Panagiotis Kanavos
    Nov 21 '18 at 16:27

















When you throw inner you'll need to await that Task at some point to propagate the exception.

– JSteward
Nov 20 '18 at 15:53





When you throw inner you'll need to await that Task at some point to propagate the exception.

– JSteward
Nov 20 '18 at 15:53













_actionBlock is long running though. I create it on application startup and under the normal course of things it keeps running for the length of the application. There's isn't a natural point in the code where I could await it's Completion task without blocking everything.

– James
Nov 20 '18 at 16:34





_actionBlock is long running though. I create it on application startup and under the normal course of things it keeps running for the length of the application. There's isn't a natural point in the code where I could await it's Completion task without blocking everything.

– James
Nov 20 '18 at 16:34













Unfortunately that's where the exception winds up. But in that event the ActionBlock is faulted and wouldn't continue processing anyway. You can handle exceptions within the flow or attach them to the result of the flow for handling outside.

– JSteward
Nov 20 '18 at 16:40





Unfortunately that's where the exception winds up. But in that event the ActionBlock is faulted and wouldn't continue processing anyway. You can handle exceptions within the flow or attach them to the result of the flow for handling outside.

– JSteward
Nov 20 '18 at 16:40













@James ActionBlocks are always long running. If you want to handle exceptions after the block completes, though a fault or normal completion, you await it. ContinueWith will only run when that ActionBlock completes anyway.

– Panagiotis Kanavos
Nov 21 '18 at 16:24





@James ActionBlocks are always long running. If you want to handle exceptions after the block completes, though a fault or normal completion, you await it. ContinueWith will only run when that ActionBlock completes anyway.

– Panagiotis Kanavos
Nov 21 '18 at 16:24













@James as for the exception not propagating, you wrote the equivalent of TaskFactory.StartNew(()=>throw new Exception());. If you don't await that task, the exception will disappear. Where do you want that error to appear anyway?

– Panagiotis Kanavos
Nov 21 '18 at 16:27





@James as for the exception not propagating, you wrote the equivalent of TaskFactory.StartNew(()=>throw new Exception());. If you don't await that task, the exception will disappear. Where do you want that error to appear anyway?

– Panagiotis Kanavos
Nov 21 '18 at 16:27












1 Answer
1






active

oldest

votes


















1














Quote from Concurrency in C# Cookbook (Stephen Cleary):




To catch exceptions from a Dataflow block, await its Completion
property. The Completion property returns a Task that will complete
when the block is completed, and if the block faults, the Completion task is also faulted.




actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 4,
});
await actionBlock.Completion;





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53394806%2ftpl-dataflow-exception-in-block-fault-handler-does-not-propagate%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Quote from Concurrency in C# Cookbook (Stephen Cleary):




    To catch exceptions from a Dataflow block, await its Completion
    property. The Completion property returns a Task that will complete
    when the block is completed, and if the block faults, the Completion task is also faulted.




    actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
    new ExecutionDataflowBlockOptions()
    {
    MaxDegreeOfParallelism = 4,
    });
    await actionBlock.Completion;





    share|improve this answer




























      1














      Quote from Concurrency in C# Cookbook (Stephen Cleary):




      To catch exceptions from a Dataflow block, await its Completion
      property. The Completion property returns a Task that will complete
      when the block is completed, and if the block faults, the Completion task is also faulted.




      actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
      new ExecutionDataflowBlockOptions()
      {
      MaxDegreeOfParallelism = 4,
      });
      await actionBlock.Completion;





      share|improve this answer


























        1












        1








        1







        Quote from Concurrency in C# Cookbook (Stephen Cleary):




        To catch exceptions from a Dataflow block, await its Completion
        property. The Completion property returns a Task that will complete
        when the block is completed, and if the block faults, the Completion task is also faulted.




        actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
        new ExecutionDataflowBlockOptions()
        {
        MaxDegreeOfParallelism = 4,
        });
        await actionBlock.Completion;





        share|improve this answer













        Quote from Concurrency in C# Cookbook (Stephen Cleary):




        To catch exceptions from a Dataflow block, await its Completion
        property. The Completion property returns a Task that will complete
        when the block is completed, and if the block faults, the Completion task is also faulted.




        actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
        new ExecutionDataflowBlockOptions()
        {
        MaxDegreeOfParallelism = 4,
        });
        await actionBlock.Completion;






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 12 '18 at 8:41









        Marius StănescuMarius Stănescu

        1,65121931




        1,65121931
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53394806%2ftpl-dataflow-exception-in-block-fault-handler-does-not-propagate%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to pass form data using jquery Ajax to insert data in database?

            National Museum of Racing and Hall of Fame

            Guess what letter conforming each word