Task#call() method invoked before task is executed - javafx

According to the documentation, Task#call() is "invoked when the Task is executed ".
Consider the following program:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.stage.Stage;
public class TestTask extends Application {
Long start;
public void start(Stage stage) {
start = System.currentTimeMillis();
new Thread(new Taskus()).start();
}
public static void main(String[] args) {
launch();
}
class Taskus extends Task<Void> {
public Taskus() {
stateProperty().addListener((obs, oldValue, newValue) -> {
try {
System.out.println(newValue + " at " + (System.currentTimeMillis()-start));
} catch (Exception e) {
e.printStackTrace();
}
});
}
public Void call() throws InterruptedException {
for (int i = 0; i < 10000; i++) {
// Could be a lot longer.
}
System.out.println("Some code already executed." + " at " + (System.currentTimeMillis()-start));
Thread.sleep(3000);
return null;
}
}
}
Executing this program gives me the following output:
Some code already executed. after 5 milliseconds
SCHEDULED after 5 milliseconds
RUNNING after 7 milliseconds
SUCCEEDED after 3005 milliseconds
Why is the call() method invoked before the task is even scheduled? This makes no sense to me. In the task where I first saw the issue my task executed a few seconds before the task went into the SCHEDULED state. What if I want to give the user some feedback on the state, and nothing happens until the task has already been executed for a few seconds?

Why is the call() method invoked before the task is even scheduled?
TLDR; version: It's not. It's merely invoked before you get notified that it's been scheduled.
You have two threads running, essentially independently: the thread you explicitly create, and the FX Application Thread. When you start your application thread, it will invoke Taskus.call() on that thread. However, changes to the the task's properties are made on the FX Application Thread via calls to Platform.runLater(...).
So when you call start() on your thread, the following occurs behind the scenes:
A new thread is started
On that thread, an internal call() method in Task is called. That method:
Schedules a runnable to execute on the FX Application Thread, that changes the stateProperty of the task to SCHEDULED
Schedules a runnable to execute on the FX Application Thread, that changes the stateProperty of the task to RUNNING
Invokes your call method
When the FX Application Thread receives the runnable that changes the state of the task from READY to SCHEDULED, and later from SCHEDULED to RUNNING, it effects those changes and notifies any listeners. Since this is on a different thread to the code in your call method, there is no "happens-before" relationship between code in your call method and code in your stateProperty listeners. In other words, there is no guarantee as to which will happen first. In particular, if the FX Application Thread is already busy doing something (rendering the UI, processing user input, processing other Runnables passed to Platform.runLater(...), etc), it will finish those before it makes the changes to the task's stateProperty.
What you are guaranteed is that the changes to SCHEDULED and to RUNNING will be scheduled on the FX Application thread (but not necessarily executed) before your call method is invoked, and that the change to SCHEDULED will be executed before the change to RUNNING is executed.
Here's an analogy. Suppose I take requests from customers to write software. Think of my workflow as the background thread. Suppose I have an admin assistant who communicates with the customers for me. Think of her workflow as the FX Application thread. So when I receive a request from a customer, I tell my admin assistant to email the customer and notify them I received the request (SCHEDULED). My admin assistant dutifully puts that on her "to-do" list. A short while later, I tell my admin assistant to email the customer telling them I have started working on their project (RUNNING), and she adds that to her "to-do" list. I then start working on the project. I do a little work on the project, and then go onto Twitter and post a tweet (your System.out.println("Some code already executed")) "Working on a project for xxx, it's really interesting!". Depending on the number of things already on my assistant's "to-do" list, it's perfectly possible the tweet may appear before she sends the emails to the customer, and so perfectly possible the customer sees that I have started work on the project before seeing the email saying the work is scheduled, even though from the perspective of my workflow, everything occurred in the correct order.
This is typically what you want: the status property is designed to be used to update the UI, so it must run on the FX Application Thread. Since you are running your task on a different thread, you presumably want it to do just that: run in a different thread of execution.
It seems unlikely to me that a change to the scheduled state would be observed a significant amount of time (more than one frame rendering pulse, typically 1/60th second) after the call method actually started executing: if this is happening you are likely blocking the FX Application thread somewhere to prevent it from seeing those changes. In your example, the time delay is clearly minimal (less than a millisecond).
If you want to do something when the task starts, but don't care which thread you do it on, just do that at the beginning of the call method. (In terms of the analogy above, this would be the equivalent of me sending the emails to the customer, instead of requesting that my assistant do it.)
If you really need code in your call method to happen after some user notification has occurred on the FX Application Thread, you need to use the following pattern:
public class Taskus extends Task<Void> {
#Override
public Void call() throws Exception {
FutureTask<Void> uiUpdate = new FutureTask<Void>(() -> {
System.out.println("Task has started");
// do some UI update here...
return null ;
});
Platform.runLater(uiUpdate);
// wait for update:
uiUpdate.get();
for (int i = 0; i < 10000; i++) {
// any VM implementation worth using is going
// to ignore this loop, by the way...
}
System.out.println("Some code already executed." + " at " + (System.currentTimeMillis()-start));
Thread.sleep(3000);
return null ;
}
}
In this example, you are guaranteed to see "Task has started" before you see "Some code already executed". Additionally, since displaying the "Task has started" method happens on the same thread (the FX Application thread) as the changes in state to SCHEDULED and RUNNING, and since displaying the "Task has started" message is scheduled after those changes in state, you are guaranteed to see the transitions to SCHEDULED and RUNNING before you see the "Task has started" message. (In terms of the analogy, this is the same as me asking my assistant to send the emails, and then not starting any work until I know she has sent them.)
Also note that if you replace your original call to
System.out.println("Some code already executed." + " at " + (System.currentTimeMillis()-start));
with
Platform.runLater(() ->
System.out.println("Some code already executed." + " at " + (System.currentTimeMillis()-start)));
then you are also guaranteed to see the calls in the order you are expecting:
SCHEDULED after 5 milliseconds
RUNNING after 7 milliseconds
Some code already executed. after 8 milliseconds
SUCCEEDED after 3008 milliseconds
This last version is the equivalent in the analogy of me asking my assistant to post the tweet for me.

Related

Why does Vertx throws a warning even with blocking attribute?

I have a Quarkus application where I use the event bus.
the code in question looks like this:
#ConsumeEvent(value = "execution-request", blocking = true)
#Transactional
#TransactionConfiguration(timeout = 3600)
public void consume(final Message<ExecutionRequest> msg) {
try {
execute(...);
} catch (final Exception e) {
// some logging
}
}
private void execute(...)
throws InterruptedException {
// it actually runs a long running task, but for
// this example this has the same effect
Thread.sleep(65000);
}
Why do I still get a
WARN [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-worker-thread-0,5,main] has been blocked for 63066 ms, time limit is 60000 ms: io.vertx.core.VertxException: Thread blocked
I'm I doing something wrong? Is the blocking parameter at the ConsumeEvent annotation not enough to let that handle in a separate Worker?
Your annotation is working as designed; the method is running in a worker thread. You can tell by both the name of the thread "vert.x-worker-thread-0", and by the 60 second timeout before the warnings were logged. The eventloop thread only has a 3 second timeout, I believe.
The default Vert.x worker thread pool is not designed for "very" long running blocking code, as stated in their docs:
Warning:
Blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the blocked thread checker. Long blocking operations should use a dedicated thread managed by the application, which can interact with verticles using the event-bus or runOnContext
That message mentions blocking for more than 10 seconds triggers a warning, but I think that's a typo; the default is actually 60.
To avoid the warning, you'll need to create a dedicated WorkerExecutor (via vertx.createSharedWorkerExecutor) configured with a very high maxExcecuteTime. However, it does not appear you can tell the #ConsumeEvent annotation to use it instead of the default worker pool, so you'd need to manually create an event bus consumer, as well, or use a regular #ConsumeEvent annotation, but call workerExectur.executeBlocking inside of it.

Can a Service starts several Tasks?

I need to use a Service which starts a Task more than once (= the same Service must run several parallelised Task). I read the JavaFX documentation, and they seem to say that a Service can run only one Task at once.
So if I call twice start with my Service object, the first Task returned by its createTask method would be stopped, as if I used restart after the first start.
However, that's not clear. As I told you, the documentation seems to tell that.
Indeed :
A Service creates and manages a Task that performs the work on the background thread.
Note that I could think they also say that a Service can have several Task started at the same time. Indeed :
a Service can be constructed declaratively and restarted on demand.
My question is : if I use N start in a row, will N Tasks be created AND KEEP EACH RUNNING ?
"If I use N start in a row, will N Tasks be created AND KEEP EACH RUNNING ?
In short, no.
"If I call start twice with my Service object..."
From the Javadocs:
public void start()
Starts this Service. The Service must be in the READY state to succeed in this call.
So if you call start() a second time without previously calling reset(), you will just get an exception. You can only call reset() if the Service is not in a RUNNING or SCHEDULED state. You can call restart(), which will have the effect of first canceling any current task, and then restarting the service. (This is what is meant by the documentation that says the "service can be restarted on demand".)
The net result of this is that a service cannot have two currently running tasks at the same time, since there is no sequence of calls that can get to that situation without throwing an IllegalStateException.
If you want multiple tasks running at once, simply create them yourself and submit them to an executor (or run each in its own thread, but an executor is preferred):
private final Executor exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
// ...
private void launchTask() {
Task<MyDataType> task = new Task<MyDataType>(){
#Override
protected Something call() {
// do work...
return new MyDataType(...);
}
};
task.setOnSucceeded(e -> { /* update UI ... */ });
task.setOnFailed(e -> { /* handle error ... */ });
exec.execute(task);
}

Azure web job singleton function is locked

I am using Azure web job to run some logic continuously. The function is a singleton function. However, I am getting "Waiting for lock" message after I tried to run this function after a restart of the web app. Does it mean that another instance of the same function is keeping the lock? How can I resolve this?
The function:
namespace Ns
{
public class Functions
{
[Singleton]
[NoAutomaticTriggerAttribute]
public static async Task ProcessMethod()
{
while(true){
//process logic here
await Task.Delay(TimeSpan.FromSeconds(20));}
}
}
}
The main program:
namespace ns
{
class Program
{
static void Main()
{
var host = new JobHost();
host.RunAndBlock();
}
}
}
The message that I got:
According to the Singleton attribute description the lock is adquired during function execution by a Blob lease.
If another function instance is triggered while this function is
running it will wait for the lock, periodically polling for it.
If you have more than one instance of your App Service Plan, this means that there are more than one Webjob and thus the Dashboard might be showing the locked status of the other Webjobs while one is running.
You can view the blob lease locks that are created on your storage account.
Another option is to try Listener Singletons but I never tried it with Manual triggers.
I disabled the production function in Azure and set the listenerlockPeriod to 15 seconds as described above.
This lessened the locking behavior significantly.

How is the batch asynchronous approach with the intuit SDK any different to the batch synchronous approach?

I have looked at the documentation for both synchronous and asynchronous approaches for the QuickBooks Online API V3. They both allow the creation of a data object and the adding of requests to a batch operation followed by the execution of the batch. In both the documentations they state:
"Batch items are executed sequentially in the order specified in the
request..."
This confuses me because I don't understand how asynchronous processing is allowed if the batch process executes each batch operation sequentially.
The documentation for asynchronous processing states at the top:
"To asynchronously access multiple data objects in a single request..."
I don't understand how this can occur if batch operations are executed sequentially within a batch process request.
Would someone kindly clarify.
In asyn call( from devkit ), calling thread doesn't wait for the response from service. You can associate a handler which will take care of that.
for Ex -
public void asyncAddAccount() throws FMSException, Exception {
Account accountIn = accountHelper.getBankAccountFields();
try {
service.addAsync(accountIn, new CallbackHandler() {
#Override
public void execute(CallbackMessage callbackMessage) {
callbackMessageResult = callbackMessage;
lock_add.countDown();
}
});
} catch (FMSException e) {
Assert.assertTrue(false, e.getMessage());
}
lock_add.await();
Account accountOut = (Account) callbackMessageResult.getEntity();
Assert.assertNotNull(accountOut);
accountHelper.verifyAccountFields(accountIn, accountOut);
}
Server always executes the requests sequentially.
In a batch, if you specify multiple operations, then server will execute it sequentially (top - down).
Thanks

Stoping web service in flex?

is it possible to stop a web service from executing?
I have a flex web application that searches clients with both full name and client id, when searching by name sometimes the usuer just types the last name and it takes a long time.
Since the app is used when clients are waiting in line, I would like to be able to stop the search and use their full name or id instead, and avoid waiting for the results and then having to search the user manually within the results.
thanks
edit: Sorry, I didn't explain myself correctly, when I meant "web service" I actually meant mx.rpc.soap.mxml.WebService, I want to stop it from waiting for the result event and the fault event. thanks.
There is actually a cancel(..) method explicitly for this purpose, though it is a little burried. Using the cancel method will cause the result and fault handlers not to be called and will also remove the busy cursor etc.
Depending on how you run your searches (ie. separate worker process etc), it is also possible to extend this by added in a cancelSearch() web service method to kill these worker processes and free up server resources etc.
private var _searchToken:AsyncToken;
public function doSearch(query:String):void
{
_searchToken = this.searchService.doSearch(query);
}
protected function doSearch_resultHandler(event:ResultEvent):void
{
trace("doSearch result");
trace("TODO: Do stuff with results");
_searchToken = null;
}
protected function doSearch_faultHandler(event:FaultEvent):void
{
trace("doSearch fault: " + event.fault);
_searchToken = null;
}
public function cancelSearch():void
{
var searchMessageId:String = _searchToken.message.messageId;
// Cancels the last service invocation or an invokation with the
// specified ID. Even though the network operation may still
// continue, no result or fault event is dispatched.
searchService.getOperation("doSearch").cancel(searchMessageId);
_searchToken = null;
trace("The search was cancelled, result/fault handlers not called");
// TODO: If your web service search method is using worker processes
// to do a search and is likely to continue processing for some time,
// you may want to implement a 'cancel()' method on the web service
// to stop any search threads that may be running.
}
Update
You could use disconnect() to remove any pending request responders, but it also disconnects the service's connection. Then call initialize().
/Update
You cannot stop the web service from executing, because that's beyond the Flex app's control, but you can limit the processing of the web service's response. For instance on the app, have a button like Cancel Search which sets a boolean bSearchCanceled to true.
The result handler for the web service call checks bSearchCanceled; if true just return.

Resources