Task status changed to RanToCompletion while stille running - task-parallel-library

I created a method which handles a few checks before starting a Task passed as a parameter.
My issue is that the task created there do not behave as expected and are quickly considered as RanToCompletion despite code is still running.
Here is an example:
public Task Main(CancellationToken localToken)
{
try
{
AddToTasker(new Task(async () => await ExtractAllOffer(localToken), localToken), TaskTypes.Extractor);
//this allows to extract only the task for the given task type through the list created in AddToTasker, actual code is not necessary the returned array is correct
Task.WaitAll(GetTasksArray(new TaskTypes[]{TaskTypes.Extractor}), localToken);
IsRunning = false;
}
}
public void AddToTasker(Task task, TaskTypes taskstype)
{
/*
* Whatever code to perform few check before starting the task
* among which referencing the task within a list which holds also the taskstype
*/
task.Start();
}
async private Task ExtractAllOffer(CancellationToken localToken)
{
// *** Do very long Stuff ***
}
The ExtractAllOffer method is a loop, with a few moment where i await external code completion. At the first await the Task.WaiAll terminates and it goes to IsRunning = false
I checked this thread but it does not seem to be the same issue as I correctly use an async task and not an async void.
Also, the code use to run properly before I shifted the Task execution within the AddToTasker method. Before I used to do like this AddToTasker(Task.Run(() => ExtractAllOffer(localToken), localToken), TaskTypes.Extractor); but I realized I needed to perform checks before starting the Task and needed to factor the checks within the AddToTasker method (I have many calls to this method).
I kind of understand that there is a flaw in how I declare or start my Task but can't figure what.
Help greatly appreciated

Thanks to #pere57 and this other thread I see that the wait only wait until the action that creates the Task finishes... which is quite fast.
I have to declare it as a Task< Task> in order to the unwrap the first Task (the action) to access the inner Task (the actual method that gets executed).
So here it goes :
public Task Main(CancellationToken localToken)
{
try
{
AddToTasker(new Task<Task>(() => ExtractAllOffer(localToken), localToken), TaskTypes.Extractor);
//this allows to extract only the task for the given task type through the list created in AddToTasker, actual code is not necessary the returned array is correct
Task.WaitAll(GetTasksArray(new TaskTypes[]{TaskTypes.Extractor}), localToken);
IsRunning = false;
}
}
public void AddToTasker(Task<Task> task, TaskTypes taskstype)
{
/*
* Whatever code to perform few check before starting the task
* among which referencing the task within a list which holds also the taskstype
*/
mylistoftask.Add(task.Unwrap()); //I have now to unwrap the task to add the inner one in my list
task.Start();
}
async private Task ExtractAllOffer(CancellationToken localToken)
{
// *** Do very long Stuff ***
}

Related

Sequential execution of Reactive tasks in reactor Java

I'm working on converting a blocking sequential orchestration framework to reactive. Right now, these tasks are dynamic and are fed into the engine by a JSON input. The engine pulls classes and executes the run() method and saves the state with the responses from each task.
How do I achieve the same chaining in reactor? If this was a static DAG, I would have chained it with flatMap or then operators but since it is dynamic, How do I proceed with executing a reactive task and collecting the output from each task?
Examples:
Non reactive interface:
public interface OrchestrationTask {
OrchestrationContext run(IngestionContext ctx);
}
Core Engine
public Status executeDAG(String id) {
IngestionContext ctx = ContextBuilder.getCtx(id);
List<OrchestrationTask> tasks = app.getEligibleTasks(id);
for(OrchestrationTask task : tasks) {
// Eligible tasks are executed sequentially and results are collected.
OrchestrationContext stepContext = task.run(ctx);
if(!evaluateResult(stepContext)) break;
}
return Status.SUCCESS;
}
Following the above example, if I convert tasks to return Mono<?> then, how do I wait or chain other tasks to operate on the result on previous tasks?
Any help is appreciated. Thanks.
Update::
Reactive Task example.
public class SampleTask implements OrchestrationTask {
#Override
public Mono<OrchestrationContext> run(OrchestrationContext context) {
// Im simulating a delay here. treat this as a long running task (web call) But the next task needs the response from the below call.
return Mono.just(context).delayElements(Duration.ofSeconds(2));
}
So i will have a series of tasks that accomplish various things but the response from each task is dependent on the previous and is stored in the Orchestration Context. Anytime an error is occurred, the orchestration context flag will be set to false and the flux should stop.
Sure, we can:
Create the flux from the task list (if it's appropriate to generate the task list reactively then you can replace that arraylist with the flux directly, if not then keep as-is);
flatMap() each task to your task.run() method (which as per the question now returns a Mono;
Ensure we only consume elements while evaluateResult() is true;
...then finally just return the SUCCESS status as before.
So putting all that together, just replace your loop & return statement with:
Flux.fromIterable(tasks)
.flatMap(task -> task.run(ctx))
.takeWhile(stepContext -> evaluateResult(stepContext))
.then(Mono.just(Status.SUCCESS));
(Since we've made it reactive, your method will obviously need to return a Mono<Status> rather than just Status too.)
Update as per the comment - if you just want this to execute "one at a time" rather than with multiple concurrently, you can use concatMap() instead of flatMap().

What's the difference between these two nservicebus statements

In one documentation they say IHandleMessages handler hast to be written this way (signature is automatically generated when I choose to "Implement interface" option in Visual Studio):
public class PlaceOrderHandler : IHandleMessages<PlaceOrder>
{
public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var orderPlaced = new OrderPlaced { OrderId = message.OrderId };
return context.Publish(orderPlaced);
}
}
While another documentation says it has to be written this way:
public class PlaceOrderHandler : IHandleMessages<PlaceOrder>
{
public async Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var orderPlaced = new OrderPlaced { OrderId = message.OrderId };
await context.Publish<OrderPlaced>(e => { e.OrderId = message.OrderId; });
}
}
I wonder what is the difference between these two statements, can someone explain in simple language?
Which option is the right one?
Both are correct options. The difference between the two is how a single asynchronous operation is handles in the Handle method.
In the first case, a Task is returned as-is. In the second case, publishing is awaited within the Handle method. The difference? In the first case no async state machine is created by the compiler as the task of publishing returned back. In the second scenario, a state machine is created.
Which option is the right one to use? They are both correct options. If a method is called frequently and you care for the unnecessary allocations not to take place, returnng a single task without awaiting is more efficient.

Handling transition to state for multiple events

I have a MassTransitStateMachine that orchestrates a process which involves creating multiple events.
Once all of the events are done, I want the state to transition to a 'clean up' phase.
Here is the relevant state declaration and filter function:
During(ImportingData,
When(DataImported)
// When we get a data imported event, mark this source as done.
.Then(MarkImportCompletedForLocation),
When(DataImported, IsAllDataImported)
// Once all are done, we can transition to cleaning up...
.Then(CleanUpSources)
.TransitionTo(CleaningUp)
);
...snip...
private static bool IsAllDataImported(EventContext<DataImportSagaState, DataImportMappingCompletedEvent> ctx)
{
return ctx.Instance.Locations.Values.All(x => x);
}
So while the state is ImportingData, I expect to receive multiple DataImported events. Each event marks its location as done so that that IsAllDataImported method can determine if we should transition to the next state.
However, if the last two DataImported events arrive at the same time, the handler for transitioning to the CleaningUp phase fires twice, and I end up trying to perform the clean up twice.
I could solve this in my own code, but I was expecting the state machine to manage this. Am I doing something wrong, or do I just need to handle the contention myself?
The solution proposed by Chris won't work in my situation because I have multiple events of the same type arriving. I need to transition only when all of those events have arrived. The CompositeEvent construct doesn't work for this use case.
My solution to this was to raise a new AllDataImported event during the MarkImportCompletedForLocation method. This method now handles determining whether all sub-imports are complete in a thread safe way.
So my state machine definition is:
During(ImportingData,
When(DataImported)
// When we get a data imported event, mark the URI in the locations list as done.
.Then(MarkImportCompletedForLocation),
When(AllDataImported)
// Once all are done, we can transition to cleaning up...
.TransitionTo(CleaningUp)
.Then(CleanUpSources)
);
The IsAllDataImported method is no longer needed as a filter.
The saga state has a Locations property:
public Dictionary<Uri, bool> Locations { get; set; }
And the MarkImportCompletedForLocation method is defined as follows:
private void MarkImportCompletedForLocation(BehaviorContext<DataImportSagaState, DataImportedEvent> ctx)
{
lock (ctx.Instance.Locations)
{
ctx.Instance.Locations[ctx.Data.ImportSource] = true;
if (ctx.Instance.Locations.Values.All(x => x))
{
var allDataImported = new AllDataImportedEvent {CorrelationId = ctx.Instance.CorrelationId};
this.CreateEventLift(AllDataImported).Raise(ctx.Instance, allDataImported);
}
}
}
(I've just written this so that I understand how the general flow will work; I recognise that the MarkImportCompletedForLocation method needs to be more defensive by verifying that keys exist in the dictionary.)
You can use a composite event to accumulate multiple events into a subsequent event that fires when the dependent events have fired. This is defined using:
CompositeEvent(() => AllDataImported, x => x.ImportStatus, DataImported, MoreDataImported);
During(ImportingData,
When(DataImported)
.Then(context => { do something with data }),
When(MoreDataImported)
.Then(context => { do smoething with more data}),
When(AllDataImported)
.Then(context => { okay, have all data now}));
Then, in your state machine state instance:
class DataImportSagaState :
SagaStateMachineInstance
{
public int ImportStatus { get; set; }
}
This should address the problem you are trying to solve, so give it a shot. Note that event order doesn't matter, they can arrive in any order as the state of which events have been received is in the ImportStatus property of the instance.
The data of the individual events is not saved, so you'll need to capture that into the state instance yourself using .Then() methods.

WindowsPhone | How to interrupt ThreadPool.QueueUserWorkItem

I'm using ThreadPool.QueueUserWorkItem for do an async task that do POST request via HTTP.
ThreadPool.QueueUserWorkItem(new WaitCallback(UploadPhoto), photoFileName);
For now I want to add possibility for a canceling upload from UI.
I have two questions:
How can I realize thread interruption?
Is ThreadPool suitable for my target?
Consider using Task.Factory.StartNew to do async work on WP7. You can use CancellationTokens to force a cancellation. This is how I do my async work. To realize an interruption, you can do the following (using Tasks):
var task = Task.Factory.StartNew( ( )=>
{
// some operation that will be cancelled
return "some value";
})
.ContinueWith( result =>
{
if(result.Status == TaskStatus.Cancelled) // you have other options here too
{
// handle the cancel
}
else
{
string val = result.Result; // will be "some value";
}
});
The ContinueWith clause chains another method to occur after the body of the first task completes (one way or another). The parameter 'result' for the ContinueWith method is the Task that the ContinueWith is chained to, and there is a property called Result on the task 'result' that is whatever return value is supplied by the preceding task.

How to implement kind of global try..finally in TPL?

I have async method that returns Task. From time to time my process is recycling/restarting. Work is interruping in the middle of the Task. Is there more or less general approach in TPL that I can at least log that Task was interruped?
I am hosting in ASP.NET, so I can use IRegisteredObject to cancel tasks with CancellationToken. I do not like this however. I need to pass CancellationToken in all methods and I have many of them.
try..finally in each method does not seem even to raise. ContinueWith also does not work
Any advice?
I have single place I start my async tasks, however each task can have any number of child tasks. To get an idea:
class CommandRunner
{
public Task Execute(object cmd, Func<object, Task> handler)
{
return handler(cmd).ContinueWith(t =>
{
if (t.State = == TaskStatus.Faulted)
{
// Handle faultes, log them
}
else if (x.Status == TaskStatus.RanToCompletion)
{
// Audit
}
})
}
}
Tasks don't just get "interrupted" somehow. They always get completed, faulted or cancelled. There is no global hook to find out about those completions. So the only option to do your logging is to either instrument the bodies of your tasks or hook up continuations for everything.

Resources