Conversation
Some issues with the original implementation still remain. This revision does not take care of them.
Also change all direct uses of the implementation class to use the interface.
Refactored a few tests to conform to the new async framework.
Add javadoc to new async packages.
@@ -47,6 +45,8 @@ | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file needs imports organized - several unused imports here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any unused imports in this file. Are you sure you commented on the right one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely looks like the right file to me. Eclipse is giving me unused import warnings for:
import com.google.common.collect.MapMaker;
...
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right. For some reason Idea was not showing me the unused imports.
{ | ||
<V, H extends AsyncTaskHandle<V>> String startTask(AsyncTask<V, H> task); | ||
|
||
<V, H extends AsyncTaskHandle<V>> void startTask(AsyncTask<V, H> task, Serializable key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When would I start a task with a key vs. without a key? I think some javadoc would be handy to provide the information.
Only for Document and Iteration so far, but could be extended to others i nthe future.
@Scope(ScopeType.STATELESS) | ||
@AutoCreate | ||
@Slf4j | ||
public class AsynchronousExecutor | ||
public class AsynchronousTaskExecutor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this class is only intended for use through TaskExecutor, it could be made package-protected to reduce the possibility of inappropriate use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't be package protected because Seam needs component classes to be public. And this needs to be a component class in order to take advantage of the @Asynchronous
annotation. That's the reason for adding the comment as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable.
What is the reason not to use it directly? Might be handy to mention that in the javadoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's because we need an executor that is able to return the handle
after starting the process in the background. Methods marked as
asynchronous should not return anything, so we need that extra level of
nesting to execute some things synchronously (like returning the
handle) and others asynchronously (the task itself). Maybe in the
future we can integrate this class more closely with
java.util.concurrent.ExecutorService, but for the time being it's not
really needed. I'll add some brief javadoc for this.
Carlos A. Munoz
Senior Software Engineer
Engineering - Internationalization
Red Hat
On Mon 26 Aug 2013 03:33:26 PM EST, David Mason wrote:
In
zanata-war/src/main/java/org/zanata/async/AsynchronousTaskExecutor.java:@scope(ScopeType.STATELESS)
@autocreate
@slf4j
-public class AsynchronousExecutor
+public class AsynchronousTaskExecutorSounds reasonable.
What is the reason not to use it directly? Might be handy to mention
that in the javadoc.—
Reply to this email directly or view it on GitHub
https://github.com/zanata/zanata-server/pull/141/files#r5971423.
} | ||
|
||
@Override | ||
public String call() throws Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method could probably be split into several smaller methods for readability - not a blocker for this merge, but worth noting somewhere.
It looks like there are several places where async tasks can be running but might not have a process handle available. Is this expected much under normal circumstances? If it isn't normal, we could probably simplify a lot of code by failing early if a handle isn't available. |
{ | ||
// Cancel any other processes | ||
this.zipFilePrepHandle.stop(); | ||
this.zipFilePrepHandle.cancel(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cancel(false)
is a little confusing at call sites like this. We can make our AsyncTaskHandle
friendlier than AbstractFuture
by adding a methods like:
public boolean cancelIfNotStarted()
{
return cancel(false);
}
public boolean forceCancel()
{
return cancel(true);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure abut this one. First, the boolean passed to the method is indicating whether the thread running the task may be interrupted while running or not (cancel(false)
doesn't really mean cancelling only if not started; some tasks understand the concept of being cancelled and will stop processing when this signal is received). Currently we don't support that thread interruption, so the boolean is meaningless really. But I'd like to leave the option open to implement such a feature, where we are able to asynchronously run tasks that were not meant to be asynchronous (an thus have no concept of "stopping"), but at the same time being able to forcefully cancel them. this might require some thought and prototyping (and might not even be possible with Seam 2), and since it wasn't really an option in the previous setup, I didn't bother going into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comment is just about readability at the call site - when someone reads a line that says:
handle.cancel(false);
they can only guess at what that might mean (and will likely guess wrong) - basically it forces them to look up the javadoc or find the implementation, which is disruptive to quickly getting an understanding of what the code does.
My suggestion here is just to wrap the parameterized method in a couple of more readable methods, so that all code that cancels an async process is more readable, so readers don't have to do a double-take and investigate when they're just trying to get a quick overview of what the code is doing, e.g. you hit a line that says:
handle.cancel()
or
handle.forceCancel()
or something else that makes sense right away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still have mixed feelings about this. One the one hand the methods are more specific, but on the other now we have three methods that do a cancel operation, most of them being logically equivalent. So, if avoiding a javadoc lookup is what you're after, you've just traded the lookup when trying to understand the code, for a lookup when trying to actually cancel an operation (and deciding which of the three cancel methods you want to use).
But it's probably not worth dragging this discussion any longer, so I'll cave and just add the methods :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, ideally the method that takes the boolean would not be there, but that's not how Java does things. Better still would be if we could do:
handle.cancel(interruptIfRunning=true)
but this isn't python.
Other minor name and documentation changes.
Not sure what you mean here. The whole idea is structured so that Carlos A. Munoz On 08/26/2013 06:47 PM, David Mason wrote:
|
public void copyTransForDocument(HDocument document, HCopyTransOptions copyTransOpts) | ||
{ | ||
Optional<CopyTransTaskHandle> asynchronousProcessHandle = | ||
AsyncUtils.getEventAsyncHandle(CopyTransTaskHandle.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eclipse is saying this is unused.
@carlosmunoz actually a closer look at the optional process handles shows that there are only a few of them in |
@davidmason The ideal (though admittedly probably not possible) would be to have any method being able to be called asynchronously or synchronously, with progress updates happening automatically. The best we have at the moment is to update progress optionally, so that nothing breaks when calling synchronously or asynchronously. We would expect not to have a handle when the process is called synchronously, and that is why |
@carlosmunoz ok, that makes sense if it can be run synchronously as well. For any operation that can report progress, reports could just be ignored when it is running synchronously. As for automatic progress updates, I think that will only ever be possible in cases where we can reasonably define a set of tasks that the async task runner could iterate over and run each - probably impossible for some operations and certainly too much to do any time soon. |
Still not sure about this duplication of cancel methods, but lets see how it goes.
…nal now. Initally though about throwing an exception, but really the estimated time might be asked for even after the process has started, so it's not really suitable to throw an exception in that case. Returning an optional seems like the next best possibility.
…efactor Conflicts: zanata-war/src/main/java/org/zanata/action/TranslationMemoryAction.java zanata-war/src/main/java/org/zanata/service/ProcessManagerService.java zanata-war/src/main/java/org/zanata/service/impl/ProcessManagerServiceImpl.java
Make sure the translation memory uses of the async classes is working properly.
👍 |
This is a refactor of the background process (now async task) mini-framework inside Zanata. The new changes make the code less verbose and it uses more JVM and Guava constructs like Future and ListenableFuture.
Some things can be expanded upon later, like adding a way to cancel a task even if it means interrupting it. The interface allows for it, but the implementation currently doesn't