I need to use actions and actors for CRUD logic in my application. I am following an architecture document that defines an action as being the synchronous part and the actor as being the asynchronous part, which makes sense. However, the actor, which writes data back to a file, only needs to do its own operations if an action has completed successfully. For example, if an entry is successfully updated, then write the data back. If the entry was not successfully updated, then don't write the data back. I was thinking of calling action.execute in an execute() function in an actor:
public void execute() {
if(action.execute()) {
executeAsynchronously();
}
}
However, this seems like it doesn't really fit in with the actor model. As more background I have a manager class that manages all the entries and data. There are add(), delete(), and update() methods in that class that each do:
public void addEntry(UserkEntry entryModel, boolean notify) {
assert entryModel != null;
synchronized (this) {
AddEntryAction action = new AddEntryAction();
UserDirectoryActor actor = new UserDirectoryActor(action);
addActor(actor);
actor.execute();
}
}
And my method to add an actor:
protected final synchronized void addActor(UserDirectoryActor actor) throws BusinessException {
for(UserDirectoryActor act : actors) {
if(act.equals(actor)) {
UserServiceFw.log.error("Actor for " + act.getAction() + " already exists");
throw new BusinessException("UserDirectoryActor could not be added for: " + act.getAction());
}
}
actors.add(actor);
}
How can I modify my code to better fit the actor model? And is the synchronization overkill?
Related
So I'm using ListenableFuture as a return type for certain operations. I expect the users to add callback to the future and then handle the success and exception cases. Now if the user cannot handle the exception, I want to have the ability to throw that exception onto the main Thread. Here's some code example:
public class SomeProcessor {
ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
public ListenableFuture<String> doStringProcessing() {
return executor.submit(() -> doWork());
}
private String doWork() {
return "stuff";
}
}
Then in a client class:
public class SomeConsumer {
public SomeConsumer (SomeProcessor processor) {
Futures.addCallback(processor.doStringProcessing(), new FutureCallback<String>() {
#Override
public void onSuccess(String result) {
// do something with result
}
#Override
public void onFailure(Throwable t) {
if (t instanceof ExceptionICanHandle) {
// great, deal with it
} else {
// HERE I want to throw on the Main thread, not on the executor's thread
// Assume somehow I can get a hold of the main thread object
mainThread.getUncaughtExceptionHandler().uncaughtException(mainThread, t);
// This above code seems wrong???
throw new RuntimeException("Won't work as this is not on the mainthread");
}
}
}, MoreExecutors.directionExecutor());
}
}
There is no direct way to do this.1
Hence, this question boils down to a combination of 2 simple things:
How do I communicate some data from a submitted task back to the code that is managing the pool itself? Which boils down to: How do I send data from one thread to another, and...
How do I throw an exception - which is trivial - throw x;.
In other words, you make the exception in your task, and do not throw it, instead, you store the object in a place the main thread can see it, and notify the main thread they need to go fetch it and throw it. Your main thread waits for this notification and upon receiving it, fetches it, and throws it.
A submitted task cannot simply 'ask' for its pool or the thread that manages it. However, that is easy enough to solve: Simply pass either the 'main thread' itself, or more likely some third object that serves as common communication line between them, to the task itself, so that task knows where to go.
Here is one simplistic approach based on the raw synchronization primitives baked into java itself:
public static void main(String[] args) {
// I am the main thread
// Fire up the executorservice here and submit tasks to it.
// then ordinarily you would let this thread end or sleep.
// instead...
ExecutorService service = ...;
AtomicReference<Throwable> err = new AtomicReference<>();
Runnable task = () -> doWork(err);
service.submit(task);
while (true) {
synchronized (err) {
Throwable t = err.get();
if (t != null) throw t;
err.wait();
}
}
}
public void doWork(AtomicReference<Throwable> envelope) {
try {
doActualWork();
catch (Throwable t) {
synchronized (envelope) {
envelope.set(t);
envelope.notifyAll();
}
}
}
There are many, many ways to send messages from one thread to another and the above is a rather finicky, primitive form. It'll do fine if you don't currently have any comms channels already available to you. But, if you already have e.g. a message queue service or the like you should probably use that instead here.
[1] Thread.stop(someThrowable) literally does this as per its own documentation. However, it doesn't work - it's not just deprecated, it has been axed entirely; calling it throws an UnsupportedOperationException on modern VMs (I think at this point 10 years worth of releases at least), and is marked deprecated with the rather ominous warning of This method is inherently unsafe. and a lot more to boot, it's not the right answer.
I have some basic project that has like four calls to some external resource, that in current version runs synchronously. What I would like to achieve is to wrap that calls into HystrixObservableCommand and then call it asynchronously.
From what I have read, after calling .observe() at the HystrixObservableCommand object, the wrapped logic should be called immediately and asynchronously. However I am doing something wrong, because it works synchronously.
In the example code, the output is Void, because I'm not interested in output (for now). That is also why I did not assigned the Observable to any object, just called constructor.observe().
#Component
public class LoggerProducer {
private static final Logger LOGGER = Logger.getLogger(LoggerProducer.class);
#Autowired
SimpMessagingTemplate template;
private void push(Iterable<Message> messages, String topic) throws Exception {
template.convertAndSend("/messages/"+topic, messages);
}
public void splitAndPush(Iterable<Message> messages) {
Map<MessageTypeEnum, List<Message>> groupByMessageType = StreamSupport.stream(messages.spliterator(), true)
.collect(Collectors.groupingBy(Message::getType));
//should be async - it's not
new CommandPushToBrowser(groupByMessageType.get(MessageTypeEnum.INFO),
MessageTypeEnum.INFO.toString().toLowerCase()).observe();
new CommandPushToBrowser(groupByMessageType.get(MessageTypeEnum.WARN),
MessageTypeEnum.WARN.toString().toLowerCase()).observe();
new CommandPushToBrowser(groupByMessageType.get(MessageTypeEnum.ERROR),
MessageTypeEnum.ERROR.toString().toLowerCase()).observe();
}
class CommandPushToBrowser extends HystrixObservableCommand<Void> {
private Iterable<Message> messages;
private String messageTypeName;
public CommandPushToBrowser(Iterable<Message> messages, String messageTypeName) {
super(HystrixCommandGroupKey.Factory.asKey("Messages"));
this.messageTypeName = messageTypeName;
this.messages = messages;
}
#Override
protected Observable<Void> construct() {
return Observable.create(new Observable.OnSubscribe<Void>() {
#Override
public void call(Subscriber<? super Void> observer) {
try {
for (int i = 0 ; i < 50 ; i ++ ) {
LOGGER.info("Count: " + i + " messageType " + messageTypeName);
}
if (null != messages) {
push(messages, messageTypeName);
LOGGER.info("Message type: " + messageTypeName + " pushed: " + messages);
}
if (!observer.isUnsubscribed()) {
observer.onCompleted();
}
} catch (Exception e) {
e.printStackTrace();
observer.onError(e);
}
}
});
}
}
}
There are some pure "test" code fragments there, as I was trying to figure out the problem, just ignore the logic, main focus is to make it run async with .observe(). I do know that I may achieve that with standard HystrixCommand, but this is not the goal.
Hope someone helps :)
Regards,
Answer was found:
"Observables do not add concurrency automatically. If you are modeling
synchronous, blocking execution with an Observable, then they will
execute synchronously.
You can easily make it asynchronous by scheduling on a thread using
subscribeOn(Schedulers.io()). Here is a simply example for wrapping a
blocking call with an Observable:
https://speakerdeck.com/benjchristensen/applying-reactive-programming-with-rxjava-at-goto-chicago-2015?slide=33
However, if you are wrapping blocking calls, you should just stick
with using HystrixCommand as that’s what it’s built for and it
defaults to running everything in a separate thread. Using
HystrixCommand.observe() will give you the concurrent, async
composition you’re looking for.
HystrixObservableCommand is intended for wrapping around async,
non-blocking Observables that don’t need extra threads."
-- Ben Christensen - Netflix Edge Engineering
Source: https://groups.google.com/forum/#!topic/hystrixoss/g7ZLIudE8Rs
I'd like my actor to wait for some event to occur, but I want it to still receive messages and proceed with messages. How can I achieve it?
My code is as follows:
class MyActor extends UntypedActor {
//onReceive implementation etc...
private void doSomething(ActorRef other){
String decision = (String) Await.result(ask(other, new String("getDecision"),1000), Duration.create(1, SECONDS));
while(decision.equals(""){
Thread.sleep(100)
decision = (String) Await.result(ask(other, new String("getDecision"),1000), Duration.create(1, SECONDS));
}
}
}
But this blocks entire actor until it receives proper decision. How can I achieve something like that without blocking my actor ?
That kind of code is the good candidate for the use of Futures.
You can find more information here: http://doc.akka.io/docs/akka/snapshot/java/futures.html
In your case, it would look like:
final ExecutionContext ec = context().dispatcher();
private void doSomething(ActorRef other){
Future<Object> decision = (Patterns.ask(other, new String("getDecision"), 1000));
decision.onSuccess(new OnSuccess<Object>() {
public void onSuccess(Object result) {
String resultString = (String) result;
System.out.println("Decision: " + result);
}
}, ec);
}
You should always try to avoid Await.result which like you said causes the thread to block. You can use callbacks such as onSuccess or onComplete to execute code once the future returns without waiting for the result.
In my application, I load a table with data.
In this tab, one column come from a webservice which can make some times to answer.
So I treat this one in pool thread to avoid to block the screen like this:
final ObservableList<StockListBean> list = FXCollections
.observableArrayList();
list.addAll(stocksListMService.getStocksListRunning());
stocksList.setItems(list);
final ExecutorService executor = Executors.newFixedThreadPool(4);
for (final StockListBean stockListBean : list) {
executor.execute(new Task<Float>() {
#Override
protected Float call() throws Exception {
logger.debug("In jfx task for {}", stockListBean.getCode());
((StockListRunningBean)stockListBean).setActualPrice(stocksListMService.getActualPrice(stockListBean.getCode()));
columnActualPrice.setVisible(false);
columnActualPrice.setVisible(true);
return 0f;
}
});
}
Threads are well execute and data are well set in beans but I don't reach to refresh the tableView.
I try code in the snapshot. I try many other ways found on the web but nothing to do, the column is desperately empty.
If I keep the thread loop but without execute the service and set a default value, the column is not empty.
It's such a real problem with screen refresh.
How can I refresh this ?
Thanks.
Assuming your StockListRunningBean uses JavaFX observable properties, so that the TableView sees the changes, you shouldn't need to do anything additional to update the table. One problem with your code is that you're making changes to the UI (via changes to the StockListRunningBean price property) from a thread that's not the FX Application Thread.
Try this refactoring:
for (final StockListBean stockListBean : list) {
final int code = stockListBean.getCode(); // assuming int, change as required
final Task<Float> task = new Task<Float>() {
#Override
protected Float call() throws Exception {
logger.debug("In jfx task for {}", code);
return stocksListMService.getActualPrice(code);
}
};
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
((StockListRunningBean)stockListBean).setActualPrice(task.getValue());
}
});
executor.execute(task);
}
Again, this assumes that your StockListRunnerBean has a
public FloatProperty actualPriceProperty() {...}
method and that the table column is properly bound to it.
I would like to have an application which either loads or saves data through a HTTP request, however the data must interact with the UI thread. Ideally, I would like a single thread to use an IF statement on a message to determine if the request is to "load" or "save".
What would be the simplest way of doing this with the smallest amount of code?
Also, do instances of Handlers run on individual threads?
EDIT: This is the code I am using now:
Handler doStuff = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 1){
// Load all the information.
// Get the ID from sharedPrefs
SharedPreferences details= getSharedPreferences("details", 0);
String ID = patDetails.getString("id", "error");
// Load up the ID from HTTP
String patInfo = httpInc.getURLContent("info.php?no="+AES.encrypt("387gk3hjbo8sgslksjho87s", ID));
// Separate all the details
patientInfo = patInfo.split("~");
}
if(msg.what == 2){
// Save the data
}
}
};
Eclipse halts the debugging and displays, "Source not found" for StrictMode.class
I suppose it's because it's using the Main thread to access the internet although it's running in individual threads.
Any idea.
Handlers do run on individual threads. Check that link. You should also check out AsyncTask.
I would propose submitting the jobs as Runnable to a single-threaded ExecutorService:
public class SomeClass {
private ExecutorService execService = Executors.newSingleThreadExecutor();
public void doSomething() {
final String someUiData = // retrieve data from UI
execService.submit(new Runnable() {
#Override
public void run() {
// so something time-consuming, which will be executed asynchronously from the UI thread
// you can also access someUiData here...
}
});
}
}
This way, the UI thread will not block whereas you can easily submit a different Runnable for different operations and the ExecutorService will completely take care of keeping it async.
Edit: If you need to interact with the UI, do so before becoming asynchronous and keep the result in final variables.