I am new to Windows Workflow and trying to write a Long Running process.
I am also trying to limit how long this process can run for.
I am calling WorkflowInvoker.Invoke to trigger my Workflow passing it a small timespan for testing.
If I try this certain activities, this seems to work perfectly.
But If I use a CodeActivity, it seems to ignore my timeout entirely.
Why is this? And how do I cause my CodeActivity to timeout if it takes too long?
An example working with a Delay Activity:
(In this example the TimeOutException is thrown)
Activity wf = new Sequence()
{
Activities =
{
new Delay()
{
Duration = TimeSpan.FromSeconds(10)
},
}
};
try
{
WorkflowInvoker.Invoke(wf, TimeSpan.FromSeconds(5));
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
An example trying to use a CodeActivity:
(In this example the TimeOutException is not thrown)
public class LongActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
Thread.Sleep(TimeSpan.FromSeconds(10));
}
}
Activity wf = new Sequence()
{
Activities =
{
new LongActivity()
}
};
try
{
WorkflowInvoker.Invoke(wf, TimeSpan.FromSeconds(5));
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
The workflow runtime can only take action when it is in charge and if your activity takes 10 seconds to execute, or sleep, the runtime can't do anything about it. It won't schedule any new activities though because there is no remaining time left and would throw a TimeoutException instead.
Normally when you have long running work you would use an asynchronous activity, either an AsyncCodeActivity or a NativeActivity with a bookmark so the runtime is in control and can abort the workflow.
Related
I'm implementing an enricher pattern (https://www.enterpriseintegrationpatterns.com/patterns/messaging/DataEnricher.html) using a command/consumer queue where the consumer is the enricher and publishes the enriched message to a separate endpoint (SQL database in this case). The consumer is running as a HostedService which implements cancellation token.
Because I'm consuming commands from one transport and publishing events to another there is a possibility that the transport I'm publishing to is down while the one I'm consuming from is up. In that case I'd like to log an error and stop my Hosted service. However, I cannot see how that would work since whatever calls the Handle method already handles exceptions, and I cannot access my cancellation token. Does anyone have any ideas?
This is a draft of what I want to do.
public async Task Handle(EditedEventData message)
{
var enricher = _enricherFactory.GetEnricher(message);
object #event = await enricher.EnrichAsync(message);
var transformers = _transformerFactory.GetTransformers(message);
var messages = new List<object>();
foreach (var transformer in transformers)
{
messages.AddRange(transformer.Transform(#event, message));
}
foreach (var item in messages)
{
try
{
await _bus.Publish(item);
}
catch (Exception ex)
{
_logger.LogCritical("Publishing event message {#item} failed with error {ex}", item, ex);
//how do I exit from here?
}
}
}
If I were you, I would come up with some kind of application service, e.g. IApplicationControlService, which you can configure to be injected into your handlers using whichever IoC container you're using.
It could look somewhat like this:
public interface IApplicationControlService
{
void RequestApplicationShutdown();
}
and then your code could simply
public class YourHandler : IHandleMessages<EditedEventData>
{
readonly IApplicationControlService applicationControlService;
public YourHandler(IApplicationControlService applicationControlService)
{
this.applicationControlService = applicationControlService;
}
public async Task Handle(EditedEventData message)
{
// (...)
foreach (var item in messages)
{
try
{
await _bus.Publish(item);
}
catch (Exception ex)
{
_logger.LogCritical("Publishing event message {#item} failed with error {ex}", item, ex);
applicationControlService.RequestApplicationShutdown();
}
}
}
}
to request the application be stopped, when an error occurs.
An implementation of IApplicationControlService could then be something like
public class BruteForceApplicationControlService : IApplicationControlService
{
public void RequestApplicationShutdown()
{
Environment.FailFast("you should probably not do THIS 😉");
}
}
or something more gentle 😁 – the point is, that you will be able to provide a way to request your application to shut down "from the outside", most likely from the place where your application is assembled (i.e. the "composition root")
I'm first to use webflux in my project, just want to set timeout in case of long period handle.
#GetMapping("/{id}")
private Mono<ResponseEntity<String>> getEmployeeById(#PathVariable
String id) {
return Mono.just(id).map(updateTweet -> {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new ResponseEntity<>(updateTweet, HttpStatus.OK);
}).timeout(Duration.ofSeconds(3)).onErrorReturn(new ResponseEntity<>("0000", HttpStatus.OK));
}
expect:in 3 seconds later, this function will return.
actual results: in 10 seconds later, this function returned.
In your code the .map and .timeout are all in subscription thread. The .sleep(10) causes the currently executing thread to sleep (temporarily cease execution) for the 10s. So when 3s timeout the thread can't execute.
You should use publishOn shifts .map to scheduler thread.
#GetMapping("/{id}")
private Mono<ResponseEntity<String>> getEmployeeById(#PathVariable
String id) {
Scheduler singleThread = Schedulers.single();
return Mono.just(id).publishOn(singleThread).map(updateTweet -> {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new ResponseEntity<>(updateTweet, HttpStatus.OK);
}).timeout(Duration.ofSeconds(3)).onErrorReturn(new ResponseEntity<>("0000", HttpStatus.OK));
}
What TimeUnit.SECONDS.sleep(10) does is invoke Thread.sleep(). This puts the current
Thread into sleep mode for 10 seconds.
Since you are doing this inside a map, the Thread that goes to sleep is the current thread. The code that waits for a timeOut is also on the current thread and so doesn't come into effect until the sleep times out. For this reason, you should avoid performing any Thread related operations when doing reactive programming.
If you want to simulate a long running process in the above code, you could either invoke an external API that you control that waits more than 3 seconds before sending a response, or use one of the delay* operators.
I'm trying to get a responsive JavaFX graphical interface while executing a cmd command.
The command I'm executing is the following.
youtube-dl.exe --audio-format mp3 --extract-audio https://www.youtube.com/watch?v=l2vy6pJSo9c
As you see this is a youtube-downloader that converts a youtube link to an mp3-file.
I want this to be executed in a second thread and not in the main FX thread.
I've solved this by implementing interface Callable in the class StartDownloadingThread.
#Override
public Process call() throws Exception {
Process p = null;
p = ExecuteCommand(localCPara1, localCPara2, localDirectory).start();
try {
Thread.sleep(30);
}catch (InterruptedException e){}
return p;
}
The method ExecuteCommand just returns a ProcessBuilder object.
I try to use Thread.sleep to make the program return to the main thread and thus making the application responsive. Unfortunately the program still freezes.
This is how the method call is called.
ExecutorService pool = Executors.newFixedThreadPool(2);
StartDownloadingThread callable = new StartDownloadingThread(parameter1, parameter2, directory);
Future future = pool.submit(callable);
Process p = (Process) future.get();
p.waitFor();
How do I make my GUI responsive using the interface Callable?
Using a executor to run a task just for you to use the get method of the Future that is returned when submitting the task does not actually free the original thread to continue with other tasks. Later you even use the waitFor method on the original thread, which is likely to take even more time than anything you do in your Callable.
For this purpose the Task class may be better suited, since it allows you to handle success/failure on the application thread using event handlers.
Also please make sure an ExecutorService is shut down after you're done submitting tasks.
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
Process p = null;
p = ExecuteCommand(localCPara1, localCPara2, localDirectory).start();
// why are you even doing this?
try {
Thread.sleep(30);
}catch (InterruptedException e){}
// do the rest of the long running things
p.waitFor();
return null;
}
};
task.setOnSucceeded(event -> {
// modify ui to show success
});
task.setOnFailed(event -> {
// modify ui to show failure
});
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(task);
// add more tasks...
// shutdown the pool not keep the jvm alive because of the pool
pool.shutdown();
I wrote a little code to download some files from internet..if user click on cancel button this must be stopped..i use the cancel() method for do it..but it didn't work.
ScheduledService<Object> service = new ScheduledService<Object>() {
protected Task<Object> createTask() {
return new Task<Object>() {
protected Object call() {
if (checkinternet()) {
downloadFiles();
}
return null;
}
};
}
};
service.start();
In buttons action event handler i called cancel method for stop service..
but it wasn't successful..
service.cancel();
How do i do that...
There is no automatic way to cancel a task or service.
From the documentation (https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm):
Cancelling the Task.
There is no reliable way in Java to stop a thread in process. However, the task must stop processing whenever cancel is called on the task. The task is supposed to check periodically during its work whether it was cancelled by using the isCancelled method within the body of the call method.
The example referenced in the above block looks like this:
Task<Integer> task = new Task<Integer>() {
#Override protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 100000; iterations++) {
if (isCancelled()) {
break;
}
System.out.println("Iteration " + iterations);
}
return iterations;
}
};
So you will have to implement the cancel logic by yourself, unfortunately.
I am working on making a scheduler, just like Windows Scheduler using Quartz.Net.
In Windows Scheduler, there is an option to stop a task from running if it takes more than the specified time. I have to implement the same in my scheduler.
But I am not able to find any extension method/setting to configure Trigger or Job accordingly.
I request some inputs or suggestions for it.
You can write small code to set a custom timout running on another thread. Implement IInterruptableJob interface and make a call to its Interrupt() method from that thread when the job should be interrupted. You can modify the following sample code as per your need. Please make necessary checks/config inputs wherever required.
public class MyCustomJob : IInterruptableJob
{
private Thread runner;
public void Execute(IJobExecutionContext context)
{
int timeOutInMinutes = 20; //Read this from some config or db.
TimeSpan timeout = TimeSpan.FromMinutes(timeOutInMinutes);
//Run your job here.
//As your job needs to be interrupted, let us create a new task for that.
var task = new Task(() =>
{
Thread.Sleep(timeout);
Interrupt();
});
task.Start();
runner = new Thread(PerformScheduledWork);
runner.Start();
}
private void PerformScheduledWork()
{
//Do what you wish to do in the schedled task.
}
public void Interrupt()
{
try
{
runner.Abort();
}
catch (Exception)
{
//log it!
}
finally
{
//do what you wish to do as a clean up task.
}
}
}