我有一个TPL数据流动作块,我用它来接收摄像机的触发消息,然后进行一些处理。如果处理任务抛出异常,则ActionBlock进入故障状态。我想向我的UI发送故障消息并向ActionBlock发送重置消息,以便它可以继续处理传入的触发消息。有没有办法将ActionBlock恢复到就绪状态(清除故障)?
好奇的代码:
using System.Threading.Tasks.Dataflow;
namespace Anonymous
{
/// <summary>
/// Provides a messaging system between objects that inherit from Actor
/// </summary>
public abstract class Actor
{
//The Actor uses an ActionBlock from the DataFlow library. An ActionBlock has an input queue you can
// post messages to and an action that will be invoked for each received message.
//The ActionBlock handles all of the threading issues internally so that we don't need to deal with
// threads or tasks. Thread-safety comes from the fact that ActionBlocks are serialized by default.
// If you send two messages to it at the same time it will buffer the second message until the first
// has been processed.
private ActionBlock<Message> _action;
...Properties omitted for brevity...
public Actor(string name, int id)
{
_name = name;
_id = id;
CreateActionBlock();
}
private void CreateActionBlock()
{
// We create an action that will convert the actor and the message to dynamic objects
// and then call the HandleMessage method. This means that the runtime will look up
// a method called ‘HandleMessage’ with a parameter of the message type and call it.
// in TPL Dataflow if an exception goes unhandled during the processing of a message,
// (HandleMessage) the exception will fault the block’s Completion task.
//Dynamic objects expose members such as properties and methods at run time, instead
// of at compile time. This enables you to create objects to work with structures that
// do not match a static type or format.
_action = new ActionBlock<Message>(message =>
{
dynamic self = this;
dynamic msg = message;
self.HandleMessage(msg); //implement HandleMessage in the derived class
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 1 // This specifies a maximum degree of parallelism of 1.
// This causes the dataflow block to process messages serially.
});
}
/// <summary>
/// Send a message to an internal ActionBlock for processing
/// </summary>
/// <param name="message"></param>
public async void SendMessage(Message message)
{
if (message.Source == null)
throw new Exception("Message source cannot be null.");
try
{
_action.Post(message);
await _action.Completion;
message = null;
//in TPL Dataflow if an exception goes unhandled during the processing of a message,
// the exception will fault the block’s Completion task.
}
catch(Exception ex)
{
_action.Completion.Dispose();
//throw new Exception("ActionBlock for " + _name + " failed.", ex);
Trace.WriteLine("ActionBlock for " + _name + " failed." + ExceptionExtensions.GetFullMessage(ex));
if (_action.Completion.IsFaulted)
{
_isFaulted = true;
_faultReason = _name + " ActionBlock encountered an exception while processing task: " + ex.ToString();
FaultMessage msg = new FaultMessage { Source = _name, FaultReason = _faultReason, IsFaulted = _isFaulted };
OnFaulted(msg);
CreateActionBlock();
}
}
}
public event EventHandler<FaultMessageEventArgs> Faulted;
public void OnFaulted(FaultMessage message)
{
Faulted?.Invoke(this, new FaultMessageEventArgs { Message = message.Copy() });
message = null;
}
/// <summary>
/// Use to await the message processing result
/// </summary>
public Task Completion
{
get
{
_action.Complete();
return _action.Completion;
}
}
}
}
答案 0 :(得分:0)
ActionBlock中的未处理异常就像应用程序中的未处理异常。不要这样做。适当处理例外情况。
在最简单的情况下,记录它或在块的委托中执行某些操作。在更复杂的场景中,您可以使用TransformBlock而不是ActionBlock,并将Succes或Failure消息发送到下游块。
您发布的代码有一些关键问题。数据流块不是代理,代理不是数据流块。当然,您可以使用其中一个构建另一个,但它们代表不同的范例。在这种情况下,您的Actor
会模拟ActionBlock
自己的API,但会出现多个错误。
例如,您不需要创建SendAsync
,块已经有了Complete()
。发送邮件后,您应不完成阻止。您无法处理任何其他消息。当您真的不想再使用ActionBlock时,只能致电void MyMethod(MyMessage message)
{
try
{
//...
}
catch(Exception exc)
{
//ToString logs the *complete exception, no need for anything more
_log.Error(exc.ToString());
}
}
var blockOptions new ExecutionDataflowBlockOptions {
BoundedCapacity=10,
NameFormat="Block for MyMessage {0} {1}"
};
var block=new ActionBlock<MyMessage>(MyMethod,blockOptions);
for(int i=0;i<10000;i++)
{
//Will await if more than 10 messages are waiting
await block.SendAsync(new MyMessage(i);
}
block.Complete();
//Await until all leftover messages are processed
await block.Completion;
。您不需要将DOP设置为1,这是默认值。
您可以将边界设置为DataflowBlock,以便一次只接受10条消息。否则,所有消息都将被缓冲,直到块找到了处理它们的机会
您可以使用以下代码替换所有代码:
Exception.ToString()
请注意对NameFormat
的通话。这将生成一个包含所有异常信息的字符串,包括调用堆栈。
.phases {
/*width: 960px;*/
}
.breadcrumb_wrapper {
color: white;
text-decoration: none;
padding: 20px 10px 20px 20px;
background: blue;
/* fallback color */
background: green;
position: relative;
display: block;
float: left;
}
.breadcrumb_wrapper ul {
list-style: none;
}
.breadcrumb {
list-style: none;
overflow: hidden;
font: 18px Sans-Serif;
}
.breadcrumb li {
float: left;
}
.breadcrumb li a {
color: white;
text-decoration: none;
padding: 20px 10px 20px 60px;
background: blue;
/* fallback color */
background: #004c89;
position: relative;
display: block;
float: left;
}
.breadcrumb li.active a {
background: #0078d7;
}
.breadcrumb li.active a::after {
border-left: 30px solid #0078d7;
}
.breadcrumb li a::after {
content: " ";
display: block;
width: 0;
height: 0;
border-top: 50px solid transparent;
/* Go big on the size, and let overflow hide */
border-bottom: 50px solid transparent;
border-left: 30px solid #004c89;
position: absolute;
top: 50%;
margin-top: -50px;
left: 100%;
z-index: 2;
}
.breadcrumb li a::before {
content: " ";
display: block;
width: 0;
height: 0;
border-top: 50px solid transparent;
border-bottom: 50px solid transparent;
border-left: 30px solid white;
position: absolute;
top: 50%;
margin-top: -50px;
margin-left: 5px;
left: 100%;
z-index: 1;
}
.breadcrumb li:first-child a {
padding-left: 10px;
}
.breadcrumb li a {
background: #004c89;
}
.breadcrumb li a:after {
border-left-color: #004c89;
}
/*
.breadcrumb li:nth-child(2) a { background: hsla(34,85%,45%,1); }
.breadcrumb li:nth-child(2) a:after { border-left-color: hsla(34,85%,45%,1); }
.breadcrumb li:nth-child(3) a { background: hsla(34,85%,55%,1); }
.breadcrumb li:nth-child(3) a:after { border-left-color: hsla(34,85%,55%,1); }
.breadcrumb li:nth-child(4) a { background: hsla(34,85%,65%,1); }
.breadcrumb li:nth-child(4) a:after { border-left-color: hsla(34,85%,65%,1); }
.breadcrumb li:nth-child(5) a { background: hsla(34,85%,75%,1); }
.breadcrumb li:nth-child(5) a:after { border-left-color: hsla(34,85%,75%,1); }
*/
.breadcrumb li a:hover {
background: #0078d7;
}
.breadcrumb li a:hover:after {
border-left-color: #0078d7 !important;
}
.first-set-li{ float:left; margin-right:50px; overflow:hidden; padding-right:33px; margin-top:20px; }
.breadcrumb_wrapper ul{ padding:0px; float:left; overflow:hidden; padding-right:40px;}
.breadcrumb .breadcrumb_wrapper li a::before{ border-left: 30px solid green; }
允许您为块指定一个名称模板,该模板可以由运行时使用块的内部名称和任务ID填充。