Dataflow(TPL) - exception handling issue? - c#

I'm not sure if i'm doing something wrong or it's an issue with Dataflow but I can't work out when Receive() throws exception.
When I run this test:
public class AsyncProblem
{
[Fact]
public void AsyncVsAwaiterProblem()
{
var max = 1000;
var noOfExceptions = 0;
for (int i = 0; i < max; i++)
{
try
{
Await().Wait();
}
catch
{
noOfExceptions++;
}
}
Assert.Equal(max,noOfExceptions);
}
public async Task Await()
{
bool firstPassed = false;
var divideBlock = new TransformBlock<int, int>((x) =>
{
if (firstPassed)
throw new ArgumentException("error");
firstPassed = true;
return 0;
});
divideBlock.Post(2);
divideBlock.Post(3); // this should cause failure;
divideBlock.Complete();
while (await divideBlock.OutputAvailableAsync())
{
var value = divideBlock.Receive(); // this should throw exception on second call
}
try
{
divideBlock.Completion.Wait();
}
catch
{
}
}
}
I'm getting inconsistent results, first run:
Xunit.Sdk.EqualExceptionAssert.Equal() Failure
Expected: 1000
Actual: 127
then run again:
Xunit.Sdk.EqualExceptionAssert.Equal() Failure
Expected: 1000
Actual: 14
Can someone confirm that it's not "on my machine" only issue?
Gist: https://gist.github.com/plentysmart/1c2ed2e925cc3f690f61

Actually, I think the confusion is due to the OutputAvailableAsync behavior. This method will return false when there will never be any more output.
When a block faults (i.e., as the result of an exception from the transformation delegate), it will clear both input and output buffers. This causes OutputAvailableAsync to return false.

Related

Modbus read and write value conflict

My colleague and I working on project, where some physical devices are connected to Modbus interface(e.g. Lamp), and an desktop app where we sending requests to modbus using NModbus package, and also from time to time(e.g. after every 1 second) reading data from Modbus. We have a classic read/write conflict. Reading has no issue, but sometimes when we writing new value to modbus, the physical lamp going crazy and changing his state every 1 second.
Reading data from modbus is in different task, so do writing new values to modbus.
What we`ve tried:
lock critical section(only writing), and ignoring reading data when new value comes. After that we have a problem with queue and very slow working
CancellationToken - had no effect, or I writing it bad
Currently we have a class that collects property date of last state change(registered in IoC) and when new writing value comes, then we updating this property, and blocking from reading data from Modbus. Unfortunately this code sometimes working, sometimes not.
Please help. We are going crazy with this issue and we don`t know how to fix it.
Edit: I posting current code.
This is task, where we executing GetCurrentState handler
public void Start()
{
var cancellationToken = _cancellationTokenSource.Token;
Task.Run(async () =>
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(ReadStateDelayInMiliseconds).ConfigureAwait(false);
if ((DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds < _userCommandThresholdInMiliseconds)
continue;
try
{
await _service.GetCurrentState().ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.Error($"Error while checking current state. Message '{ex.Message}', Stack trace: '{ex.StackTrace}'.");
}
}
}, cancellationToken);
}
This is GetCurrentState handler, where we reading data from Modbus
protected override IgnisLightState Handle(GetState request)
{
if ((DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds <= _configuration.UserCommandThresholdInMiliseconds)
{
Logger.Debug($"Ignore before read state from lights, time after last execution: '{(DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds}'.");
return _state;
}
var currentLightState = _state.DeepClone();
foreach (var head in currentLightState.Heads)
{
try
{
ushort startAddress = 0x0000;
ushort numberOfPointsToRead = 0x0006;
var values = _modbusMaster.ReadHoldingRegisters((byte)head.UniqueId, startAddress, numberOfPointsToRead);
var isOn = values[IgnisRegistry.On.Value];
var isEndo = values[IgnisRegistry.Endo.Value];
var isCentrum = values[IgnisRegistry.Centrum.Value];
var tempValue = values[IgnisRegistry.Temp.Value];
var illuminanceValue = values[IgnisRegistry.Vol.Value];
head.ColorValue = Convert.ToInt32(tempValue);
head.IlluminanceValue = Convert.ToInt32(illuminanceValue);
head.IsCentrumOn = Convert.ToBoolean(isCentrum);
head.IsEndoOn = Convert.ToBoolean(isEndo);
head.IsTurnedOn = Convert.ToBoolean(isOn);
if (currentLightState.CameraState != null &&
_configuration.CameraHeadId.HasValue &&
_configuration.CameraHeadId.Value == head.UniqueId)
{
var camMode = values[IgnisRegistry.Cam.Value];
currentLightState.CameraState.IsTurnedOn = Convert.ToBoolean(isOn);
currentLightState.CameraState.CurrentMode = (IgnisCameraMode)Convert.ToInt32(camMode);
}
}
catch (Exception ex)
{
Logger.ErrorFixed(ex, $"Error while getting data from headId {head.UniqueId}.");
}
}
if (_state.Equals(currentLightState)
|| (DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds < _configuration.UserCommandThresholdInMiliseconds)
{
Logger.Debug($"Ignore after read state from lights, time after last execution: '{(DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds}'.");
return _state;
}
foreach (var currentHeadState in currentLightState.Heads)
{
_lightHeadStateUpdater.UpdateState(currentHeadState);
}
Logger.Debug($"Broadcast new state to clients '{JsonConvert.SerializeObject(currentLightState)}'.");
_hubContext.Clients.All.StateChanged(currentLightState);
return currentLightState;
}
This is an Turn on lamp handler where we writing new value to modbus:
protected override Response Handle(TurnOn request)
{
_lastCommandExecutionTimeContainer.SetLastCommandExecutionTime(DateTime.Now);
if (request.HeadId <= 0
|| !_state.Heads.Any(x=>x.UniqueId == request.HeadId))
{
return ResponseFactory.FromError(Error.NotExist);
}
var headState = _state.Heads.Single(x=>x.UniqueId == request.HeadId);
if (headState.IsTurnedOn)
return ResponseFactory.FromError(Error.AlreadyAsRequested);
_modbusMaster.WriteSingleRegister((byte)request.HeadId, IgnisRegistry.On.Value, 0x0001);
headState.IsTurnedOn = true;
if (_state.CameraState != null &&
_ignisLightConfiguration.CameraHeadId.HasValue &&
_ignisLightConfiguration.CameraHeadId.Value == request.HeadId)
{
_state.CameraState.IsTurnedOn = true;
}
Logger.Trace($"Turn head lamp {request.HeadId} on.");
_hubContext.Clients.All.HeadStateChanged(headState);
return ResponseFactory.Success;
}

Assign passed functions result to object with variable type in C#

For an integration I'm running as a service once a day, I need to assign the result of API-calls to local variables. However, those API's might at any time decide to throw a 401 error, in which case I just want to try again, up to three times.
I've got a functioning code to do that:
List<APIEntityProject> projectList = null;
private bool SetProjectList(){
const maxRetries = 3;
const RetryPause = 3000;
int retries = 0;
do
{
try
{
projectList = ProjApi.GetProject(activeWorkspace.WorkspaceCode);
}
catch (ApiException e)
{
if (e.ErrorCode == 401) // Unauthorized error (e.g. user doesn't have access to this Workspace
{
Log.Warning("Unauthorized error while fetching projects from Workspace, try {retries}",retries);
retries++;
System.Threading.Thread.Sleep(RetryPause * retries);//Waits 3 and then 6 seconds before retrying.
}
else throw;
}
} while (projectList == null || retries < maxRetries);
if (retries == maxRetries)
{
Log.Error("An error has occured while trying to retrieve affected Projects, skipped document");
errorCount++;
return false;
}
return true;
}
But unfortunately I need to replicate this Logic so often I would like to use it in a function e.g. RetryNTimes (similar to This Solution
List<APIEntityProject> projectList = null;
List<APIEntityWBS> WBSList = null;
List<APIEntitySopeItem> SIList = null;
List<APIEntityScopeAsignment> SAList = null;
List<APIEntityActivity> ActList = null;
...
RetryNTimes(projectList,ProjApi.GetProject(activeWorkspace.WorkspaceCode),3,3000,"ProjectList");
RetryNTimes(WBSList, WBSApi.GetAllWBS(activeProject.ProjectID),3,3000,"WBSList");
RetryNTimes(SIList, SIApi.GetAllScopeItems(activeProject.ProjectID),3,3000,"ScopeItemsList");
RetryNTimes(SAList, SAApi.GetAllScopeAssignments(activeProject.ProjectID),3,3000,"ScopeAssignmentsList");
RetryNTimes(ActList, ActApi.GetAllActivities(activeProject.ProjectID),3,3000,"ActivityList");
...
private bool RetryNTimes(T object, Func<T> func, int times, int WaitInterval, string etext){
do
{
try
{
object = func();
}
catch (ApiException e)
{
if (e.ErrorCode == 401)
{
retries++;
Log.Warning("Unauthorized error while fetching {APIErrorSubject}, try {retries}",eText,retries);
System.Threading.Thread.Sleep(RetryPause * retries);//Waits 3 and then 6 seconds before retrying.
}
else throw;
}
} while (object == null || retries < maxRetries);
if (retries == maxRetries)
{
Log.Error("An error has occured while trying to retrieve {APIErrorSubject}, skipped document",eText);
errorCount++;
return false;
}
return true;
}
I've also read through typedef and function pointers but I'm not sure if it's possible to do with variable types.
Any Ideas?
That article refers to C language. In C# you can use delegates. Here's a link to start you off.
Based on the idea of asawyer and by looking through some other examples of delegates I've been able to make it work.
static T2 TryNTimes<T1,T2>(Func<T1,T2> func,T1 obj, int times, int WaitInterval)
{
while (times > 0)
{
try
{
T2 result = func.Invoke(obj);
return result;
}
catch (Exception e)
{
if (--times <= 0)
throw;
System.Threading.Thread.Sleep(WaitInterval * times);
}
}
return default;
}
Now I need only 2 steps in my main function
activeWorkspace = TryNTimes(WrkApi.WorkspaceCodeWorkspaceCodeFindByName17, ServiceSettings.sqlConnection.Workspace, 3, 3000)[0];
ProjectList = TryNTimes(WrkApi.GetProjectsByWorkspaceCode, activeWorkspace.code, 3, 3000);
The first one can still generate an error as the default List is empty and you can't take 0th element then. But I guess I can find another way around that issue.

System.AggregateException at System.Threading.Tasks.TaskExceptionHolder.Finalize()

Update:
Adding TaskCreationOptions.LongRunning solved the issue but is this a good approach ? If not, what is the best solution to get over this exception ?
There is an issue i am trying to troubleshoot. I have implemented the suggestions that were provided in StackOverFlow but those have not helped solve the issue. I have used other alternatives like ContinuwWith option instead of Task.WaitAll by attaching the extension method. This did not help either .
I have put Ex.handle { } and i have tried throw ex in the Catch(aggrgateException ex) in the exceptions but that did not help to catch the actual exception.
I have only .Net 4.0 installed so i cannot try the .Net 4.5 resolution to solve this
The exception that i have been getting all the time is
"System.AggregateException:" The task's exception was not observed either by waiting on the task or accessing the Exception property "
After this it simply kills worker process and the App crashes and i see an entry in the EventViewer
Any help here here will be appreciated.
We have the below code:
Task<List<MyBusinessObject>>[] tasks = new Task<List<MyBusinessObject>>[MyCollection.Count];
for (int i = 0; i < MyCollection.Count; i++)
{
MyDTO dto = new MyDTO();
--Some Property Assignment for the MyDTO object--
tasks[i] = Task<List<MyBusinessObject>>.Factory.StartNew(MyDelegate, dto)
}
try
{
Task.WaitAll(tasks);
}
catch (AggregateException e)
{
AddToLogFile("Exceptions thrown by WaitAll() : ");
for (int j = 0; j < e.InnerExceptions.Count; j++)
{
AddToLogFile(e.InnerExceptions[j].ToString());
}
}
catch(Exception ex)
{
AddToLogFile(ex.Message);
}
Second Alternative
public Static Class Extensions
{
public static void LogExceptions(this Task<List<<MyBusinessObject>> task)
{
task.ContinueWith(t =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
{
AddToLogFile("Task Exception: " + exception.Message);
}
},
TaskContinuationOptions.OnlyOnFaulted);
}
}
//In a different class call the extension method after starting the new tasks
Task<List<MyBusinessObject>>[] tasks = new Task<List<MyBusinessObject>>[MyCollection.Count];
for (int i = 0; i < MyCollection.Count; i++)
{
MyDTO dto = new MyDTO();
--Some Property Assignment for the MyDTO object--
tasks[i] = Task<List<MyBusinessObject>>.Factory.StartNew(MyDelegate, dto).LogExceptions()
}
Instead of creating a new tasks for each iteration all at one time, i created the new task for 100 tasks every time. I then waited till all the tasks were complete and spwaned off another 100 tasks till all the tasks were finished
int count = Mycollection.Count();
Task>[] tasks;
int i = 0;
int j;
while (i < count)
{
j = 0;
tasks = new Task<List<MyBusinessObject>>[nbrOfTasks];
foreach (var p in Mycollection.Skip(i).Take(nbrOfTasks))
{
MyRequestDto dto = new MyRequestDto ();
--Some Proerty Assignment
tasks[j] = Task<List<MyBusinessObject>>.Factory.StartNew(MyDelegate, dto);
i++;
j++;
}
try
{
// Wait for all the tasks to finish.
if (tasks != null && tasks.Count() > 0)
{
tasks = tasks.Where(t => t != null).ToArray();
Task.WaitAll(tasks);
}
}
catch (AggregateException e)
{
}
This is to do with the memory avaiable to service multiple tasks. If the required RAM was not available to service the concurrent tasks along the way, the App Would just crash.That is why it is best to spawn limited nbr of tasks. Instead of spwaning multiple and leaving it to the threadpool to manage.

The best way (pattern) to execute something while exception is thown

Below is a code showing tries to encapsulate a logic to re-run something while an exception is being catch.
Does exist patterns or something else to do that ? Or what improvements would you suggest to that code ?
public static void DoWhileFailing(int triesAmount, int pauseAmongTries, Action codeToTryRun) {
bool passed = false;
Exception lastException = null;
for (int i = 0; !passed && i < triesAmount; i++) {
try {
if (i > 0) {
Thread.Sleep(pauseAmongTries);
}
codeToTryRun();
passed = true;
} catch(Exception e) {
lastException = e;
}
}
if (!passed && lastException != null) {
throw new Exception(String.Format("Something failed more than {0} times. That is the last exception catched.", triesAmount), lastException);
}
}
I would re-write this to eliminate a few variables, but in general your code is OK:
public static void DoWhileFailing(int triesAmount, int pauseAmongTries, Action codeToTryRun) {
if (triesAmount<= 0) {
throw new ArgumentException("triesAmount");
}
Exception ex = null;
for (int i = 0; i < triesAmount; i++) {
try {
codeToTryRun();
return;
} catch(Exception e) {
ex = e;
}
Thread.Sleep(pauseAmongTries);
}
throw new Exception(String.Format("Something failed more than {0} times. That is the last exception catched.", triesAmount, ex);
}
I wrote the following code to do basically the same thing. It also lets you specifiy the type of Exception to catch and a Func that determines if the current iteration should throw the exception or continue retrying.
public static void RetryBeforeThrow<T>(
this Action action,
Func<T, int, bool> shouldThrow,
int waitTime) where T : Exception
{
if (action == null)
throw new ArgumentNullException("action");
if (shouldThrow == null)
throw new ArgumentNullException("shouldThrow");
if (waitTime <= 0)
throw new ArgumentException("Should be greater than zero.", "waitTime");
int tries = 0;
do
{
try
{
action();
return;
}
catch (T ex)
{
if (shouldThrow(ex, ++tries))
throw;
Thread.Sleep(waitTime);
}
}
while (true);
}
Then you can call it like this
Action a = () =>
{
//do stuff
};
a.RetryBeforeThrow<Exception>((e, i) => i >= 5, 1000);
And you can specify any exception type and you can check the exception in the Func to determine if it is an exception that you want to throw or to continue to retry. This gives you the ability to throw your own exceptions in your Action that will stop the retries from occurring.
I don't see anything wrong with the code, I would just question your assumptions.
A couple of problems that I see:
Clients need to understand the failure modes of the called action to choose the right parameters.
The action could fail intermittently, which is a capacity killer. Code like this can't scale well.
Clients can wait for an indeterminate amount of time for the action to complete.
All exceptions but the last will be swallowed, which could hide important diagnostic information.
Depending on your needs, your code might suffice, but for a more robust way to encapsulate an unreliable resource, take a look at the circuit breaker pattern.

List<T>Get Chunk Number being executed

I am breaking a list into chunks and processing it as below:
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
do something
}
catch
{
print error
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this IEnumerable<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
foreach (var item in sourceList)
{
chunkReturn.Add(item);
if (chunkReturn.Count == chunkSize)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
if (chunkReturn.Any())
{
yield return chunkReturn;
}
}
}
If there is an error, I wish to run the chunk again. Is it possible to find the particular chunk number where we received the error and run that again ?
The batches have to be executed in sequential order .So if batch#2 generates an error, then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good .
List<Chunk> failedChunks = new List<Chunk>();
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
//do something
}
catch
{
//print error
failedChunks.Add(partiallist);
}
}
// attempt to re-process failed chunks here
I propose this answer based on your comment to Aaron's answer.
The batches have to be executed in sequential order .So if 2 is a problem , then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good.
foreach (var partialist in breaklistinchunks(chunksize))
{
int fails = 0;
bool success = false;
do
{
try
{
// do your action
success = true; // should be on the last line before the 'catch'
}
catch
{
fails += 1;
// do something about error before running again
}
}while (!success && fails < 2);
// exit the iteration if not successful and fails is 2
if (!success && fails >= 2)
break;
}
I made a possible solution for you if you don't mind switching from Enumerable to Queue, which kind of fits given the requirements...
void Main()
{
var list = new Queue<int>();
list.Enqueue(1);
list.Enqueue(2);
list.Enqueue(3);
list.Enqueue(4);
list.Enqueue(5);
var random = new Random();
int chunksize = 2;
foreach (var chunk in list.BreakListinChunks(chunksize))
{
foreach (var item in chunk)
{
try
{
if(random.Next(0, 3) == 0) // 1 in 3 chance of error
throw new Exception(item + " is a problem");
else
Console.WriteLine (item + " is OK");
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
list.Enqueue(item);
}
}
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this Queue<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
while(sourceList.Count > 0)
{
chunkReturn.Add(sourceList.Dequeue());
if (chunkReturn.Count == chunkSize || sourceList.Count == 0)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
}
}
Outputs
1 is a problem
2 is OK
3 is a problem
4 is a problem
5 is a problem
1 is a problem
3 is OK
4 is OK
5 is OK
1 is a problem
1 is OK
One possibility would be to use a for loop instead of a foreach loop and use the counter as a means to determine where an error occurred. Then you could continue from where you left off.
You can use break to exit out of the loop as soon as a chunk fails twice:
foreach (var partialList in breaklistinchunks(chunksize))
{
if(!TryOperation(partialList) && !TryOperation(partialList))
{
break;
}
}
private bool TryOperation<T>(List<T> list)
{
try
{
// do something
}
catch
{
// print error
return false;
}
return true;
}
You could even make the loop into a one-liner with LINQ, but it is generally bad practice to combine LINQ with side-effects, and it's not very readable:
breaklistinchunks(chunksize).TakeWhile(x => TryOperation(x) || TryOperation(x));

Categories