TPL Dataflow, Exception in block fault handler does not propagate
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
|
show 1 more comment
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
When youthrow inneryou'll need toawaitthatTaskat 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 theActionBlockis 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, youawaitit.ContinueWithwill 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 ofTaskFactory.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
|
show 1 more comment
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
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
c# task-parallel-library tpl-dataflow
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 youthrow inneryou'll need toawaitthatTaskat 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 theActionBlockis 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, youawaitit.ContinueWithwill 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 ofTaskFactory.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
|
show 1 more comment
When youthrow inneryou'll need toawaitthatTaskat 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 theActionBlockis 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, youawaitit.ContinueWithwill 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 ofTaskFactory.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
|
show 1 more comment
1 Answer
1
active
oldest
votes
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;
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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;
add a comment |
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;
add a comment |
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;
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;
answered Dec 12 '18 at 8:41
Marius StănescuMarius Stănescu
1,65121931
1,65121931
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
When you
throw inneryou'll need toawaitthatTaskat 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
ActionBlockis 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
awaitit.ContinueWithwill 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