Finish workflow when activity goes wrong - elsa-workflows

I have a workflow that executes a couple of activities. When the activity finish, it returns an Outcome either Done or Cancel, from outside and before running the next activity, I need to check if the previous activity was ok or not, in case not, I need to cancel the workflow. I have this
public class CreateEmployee : IWorkflow
{
public void Build(IWorkflowBuilder builder)
{
builder
.WithDisplayName(this.GetType().Name)
.Then<GetDataById>(x => x.WithDisplayName(x.ActivityType.Name))
.When(OutcomeNames.Cancel).Finish()
.Then<InsertEmployee>(x => x.WithDisplayName(x.ActivityType.Name))
.When(OutcomeNames.Cancel).Finish()
.Then<InsertMapping>(x => x.WithDisplayName(x.ActivityType.Name))
.When(OutcomeNames.Cancel).Finish();
}
}
For example, after executing activity GetDataById, if the return is "Cancel", I call Finish(), is this going to stop just the activity and continue the workflow or the workflow will stop completely? I'm not able to test it because I'm using DI and I need to prepare the whole unit test, because I didn't find anything directly related to cancel the whole workflow

I'm not sure if I have fully understood your question, but in the documentation about finish activity it's stated that:
when this activity is used within a workflow, the workflow instance
will enter the Finished state. When used in a child composite
activity, that activity will stop execution and yield back control to
its container. However, it will not stop workflow execution itself.

Related

MVC ActionResult trigger Async Task before return View()

I'm trying to achieve something like this:
[HttpPost]
public ActionResult PostData()
{
// 1. Need to trigger an async operation for some long processes
// Trying to trigger SideProcess() async controller
// Return to view to allow user do other stuff without waiting for above process to complete
return View("Listing", "Users");
}
public async Task<ActionResult> SideProcess()
{
...
}
Can I use async task method like above? Because I definitely have to call PostData() first on a button click. Otherwise most likely I have to use a different method.
You can, by not await-ing the result. This has some drawbacks though. (E.g. what happens if an error occurrs?)
It is better to run the async operation in via Task.Run() in such cases, since unhandled exceptions will trigger the TaskScheduler.UnobservedTaskException and don't mess with your controller action.
Task.Run(SideProcess);
I tend to use Hangfire for such problems in all of my projects and never had an issue. I would recommend and prefer it over the above solution. Comes with very handy oob features for managing BackgroundJobs (including a dashboard, automatic retry mechanisms and many more) while beeing testable too.
Doing that, you won't have any guarantees that your long running process will finish. ASP.NET was purposely not built for that.
But if you have to queue some background work, use HostingEnvironment.QueueBackgroundWorkItem.
Beware of the remarks:
Differs from a normal ThreadPool work item in that ASP.NET can keep track of how many work items registered through this API are currently running, and the ASP.NET runtime will try to delay AppDomain shutdown until these work items have finished executing. This API cannot be called outside of an ASP.NET-managed AppDomain. The provided CancellationToken will be signaled when the application is shutting down.

Async table creation and query advantages / disadvantages

In my application I have the following:
db2.CreateTable<CategoryGroup>();
db2.CreateTable<Category>();
db2.CreateTable<CategoryGroupSource>();
db2.CreateTable<CategorySource>();
db2.CreateTable<Phrase>();
db2.CreateTable<PhraseSource>();
db2.CreateTable<Score>();
db2.CreateTable<Setting>();
From what I understand there is an Async way to do this also:
database.CreateTableAsync<TodoItem>().Wait();
Can someone explain if there is any advantage in me using the Async way and do people normally always use the Async?
Also are there likely to be benefits if I use this type of Async query:
public Task<TodoItem> GetItemAsync(int id)
{
return database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
}
When calling the methods on the main (UI) thread everything on the UI stops for as long as it takes that method to execute. If db2.CreateTable<CategoryGroup>() doesn't take up much time when doing it's thing, it shouldn't be a problem.
Doing a lot of time consuming actions straight after each other might affect your UI and make it freeze.
Calling the *Async variant of the method moves the work to a background thread, via the task API. Calling Wait() on that task, though, makes the current thread (in this case the UI thread) wait for the task to finish, and you're stuck with the same problem.
You should always await tasks: await database.CreateTableAsync<TodoItem>(). This will let it execute on a background thread and not make the current thread wait for it to finish. The next line in your code won't be executed until the Task is finished though. When you write the code, it makes the `Async variant look like it's behaving like the regular version.
Personally, I'd probably move all the methods into a task and just await that. That way you're not returning to the UI thread between each task to execute the next one:
await Task.Run(() =>
{
db2.CreateTable<CategoryGroup>();
db2.CreateTable<Category>();
db2.CreateTable<CategoryGroupSource>();
db2.CreateTable<CategorySource>();
db2.CreateTable<Phrase>();
db2.CreateTable<PhraseSource>();
db2.CreateTable<Score>();
db2.CreateTable<Setting>();
}
In this case you're making the database do all it's work on a background thread (and not freezing the UI while it's doing it). It then returns the result to the UI thread to enable you to update UI.
public Task<TodoItem> GetItemAsync(int id)
{
return database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
}

Spring #Async cancel and start?

I have a spring MVC app where a user can kick off a Report generation via button click. This process could take few minutes ~ 10-20 mins.
I use springs #Async annotation around the service call so that report generation happens asynchronously. While I pop a message to user indicating job is currently running.
Now What I want to do is, if another user (Admin) can kick off Report generation via the button which should cancel/stop currently running #Async task and restart the new task.
To do this, I call the
.. ..
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone())
future.cancel(true);
service.generateReport(id);
How can make it so that "service.generateReport" waits while the future cancel task kills all the running threads?
According to the documentation, after i call future.cancel(true), isDone will return true as well as isCancelled will return true. So there is no way of knowing the job is actually cancelled.
I can only start new report generation when old one is cancelled or completed so that it would not dirty data.
From documentation about cancel() method,
Subsequent calls to isCancelled() will always return true if this method returned true
Try this.
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone()){
boolean terminatedImmediately=future.cancel(true);
if(terminatedImmediately)
service.generateReport(id);
else
//Inform user existing job couldn't be stopped.And to try again later
}
Assuming the code above runs in thread A, and your recently cancelled report is running in thread B, then you need thread A to stop before service.generateReport(id) and wait until thread B is completes / cancelled.
One approach to achieve this is to use Semaphore. Assuming there can be only 1 report running concurrently, first create a semaphore object acccessible by all threads (normally on the report runner service class)
Semaphore semaphore = new Semaphore(1);
At any point on your code where you need to run the report, call the acquire() method. This method will block until a permit is available. Similarly when the report execution is finished / cancelled, make sure release() is called. Release method will put the permit back and wakes up other waiting thread.
semaphore.acquire();
// run report..
semaphore.release();

android: AsyncTask onPostExecute keep working even if start new activity on doInBackground

i am building an application for clients to get questions from server and answer it, if the server doesn't have questions i want to go to new screen and print message that try again in few minutes, getting questions is in AsyncTask , if the server doesn't have questions , it will sends in the header of the responds, a header isFindAQuestion with the value false, here is the code on client to ensure if false , i print on LogCat and i see the message = false, but my problems that even if i start new activity with the intent, this activity keep working and show me exception and it is null pointer exception because on the onPostExceute will take a parmeter null and try to process it, i put finish() in the end of false statement but doesn't finish the activity
if (response.getFirstHeader("isFindAQuestion").getValue()
.toString().equals("false")) {
Log.d("message", "false");
Bundle basket = new Bundle();
basket.putString("Message", "sorry no enought questions");
Intent goToAnswerQuestion = new Intent(AnswerQuestion.this,
FinishTime.class);
goToAnswerQuestion.putExtras(basket);
startActivity(goToAnswerQuestion);
finish();
}
Editis it because AsyncTask is working on thread so if the activity is finished, that thread will keep working? and if so how can i stop that thread?
doInBackground is not executed in the UI thread, but in a separeted thread:
invoked on the background thread immediately after onPreExecute()
finishes executing. This step is used to perform background
computation that can take a long time.
If you want to stop your background operation and perform some activities on the UI thread the better thing is to call cancel() and then perform all the stuff you want in the onCancelled callback wich is executed on the UI thread.
From the AsyncTask documentation:
A task can be cancelled at any time by invoking cancel(boolean).
Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
protected void onCancelled (Result result)
Runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished.
The default implementation simply invokes onCancelled() and ignores the result. If you write your own implementation, do not call super.onCancelled(result).

Eclipse RCP: Display.getDefault().asyncExec still blocking my GUI

I have a simple viewPart offering some text fields to enter parameters for a selenium test. After filling out these fields the user may start the test which approx. needs 30-45 minutes to run. I want my GUI to be alive during this test giving users the chance to do other things. I need a progress monitor.
I tried to put the selenium test in a job containing Display.getDefault().asyncExec to run it. But my GUI freezes after some seconds giving the busyindicator. The selenium does not update any other view but the progress monitor.
Is there another way to ensure that the job wont block my GUI?
Best,
Mirco
Everything executed in (a)syncExec is using the display thread and therefore blocking your UI until it returns. I suggest you use Eclipse Jobs. This will use the progress indicator that the workbench already offers out of the box.
I would suggest to split your code into code that updates the UI and the code that executes other business. Execute all of it in a separate thread, and when you need to retrieve or set some action to the UI then use the "Display.getDefault().asyncExec".
Thread thread = new Thread("Testing") {
// some shared members
public void run() {
someBusiness();
// or use syncExec if you need your thread
// to wait for the action to finish
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
// UI stuff here
// data retrieval
// values setting
// actions trigging
// but no business
}
});
someBusiness();
};
thread.start();

Resources