Vert.x: Verticle custom startFuture handler is always rewritten - vert.x

Vert.x v3.5.1.
There is my custom start method of Verticle:
#Override
public void start(Future<Void> startFuture) throws Exception {
startFuture.setHandler(event -> {
if (event.succeeded()) {
logger.info("Server started on port: {}", 8080);
} else {
logger.warn("Failed to start: {}", event.cause());
}
});
vertx.createHttpServer()
.requestHandler(router()::accept)
.listen(8080, event -> {
if (event.succeeded()) {
startFuture.complete();
} else {
startFuture.fail(event.cause());
}
});
}
I expect that my custom handler will be invoked when future completes. But it doesn't!
In debug mode I see that FutureImpl::setHandler is called twice: once with my custom handler, and then with DeploymentManager's handler during doDeploy.
So the latest handler is applied.
The question is: is it possible to specify custom callback for Verticle start? If yes how can I do it?
Thank you in advance.

You're not supposed to change the handler of the startFuture, as it is owned by the caller. So simply, don't do that :) The future is used to signal that you're done with your start-code, and not to define what should be done, once you're done.
In your concrete example it'd be better to write the logs once the http server came up, and then indicate to the startFuture, that you're done with your code execution.
#Override
public void start(Future<Void> startFuture) throws Exception {
vertx.createHttpServer()
.requestHandler(router()::accept)
.listen(8080, event -> {
if (event.succeeded()) {
logger.info("Server started on port: {}", 8080);
startFuture.complete();
} else {
logger.warn("Failed to start: {}", event.cause());
startFuture.fail(event.cause());
}
});
}

At first, write your verticle as a AbstractVerticle extension. And do not override start(Future) method. Instead use start() method. It will be called from AbstractVerticle.start(Future), and you can specify that future in Vertx.deployVerticle(verticle, options, future) method.
For example:
You have some verticle. Do in it start() method only initialization tasks:
#Override
public void start() throws Exception {
vertx.eventbus().consume(address, m -> {
// consumer code skipped
});
}
and verticle registration:
final DeploymentOptions opts = new DeploymentOptions().setWorker(true);
vertx.deployVerticle(verticle, opts, event -> {
if (event.succeeded()) {
log.info("Verticle successfully deployed. DeploymentId: " + event.result());
} else {
log.error("Verticle failed to deploy. Cause: " + event.cause().getMessage(), event.cause());
}
});
That's all :)

Related

Vertx - stop method in verticle is not guaranteed

If you run the following code multiple times you will see the inconsistency: some times there are 3 lines displayed, some times there are only 2 lines displayed (the one missing is "Successfully stopped MyVerticle"). Why the .stop method is not called?
public class Main {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.rxDeployVerticle(new MyVerticle()).subscribe();
Runtime.getRuntime().addShutdownHook(
new Thread(() -> {
//vertx.deploymentIDs().forEach( deploymentId -> vertx.undeploy(deploymentId));
vertx.close(result -> System.out.println("Result" + result));
System.out.println("Successfully stopped Vertx");
})
);
}
}
class MyVerticle extends AbstractVerticle {
#Override
public void start(Future<Void> startFuture) {
System.out.println("Successfully started MyVerticle");
startFuture.complete();
}
#Override
public void stop(Future<Void> stopFuture) {
System.out.println("Successfully stopped MyVerticle");
stopFuture.complete();
}
}
The method stop() is invoked when Vert.x undeploys a verticle.
When terminating your application, Vert.x will attempt to undeploy the verticles as well, but it's a race between event loop still running and your application shutting down.

SingleObserver.onError called on background thread instead of main thread

Well as I understood from the documentation using singel.observeOn(Scheduler) will guarantee that any downstream event will be executed on that scheduler.
Apparently the onError called on the same scheduler that thrown the error as I receiving this error -
> Caused by:java.lang.IllegalStateException: Cannot invoke setValue on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:443)
at androidx.lifecycle.LiveData.setValue(LiveData.java:286)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at com.bonimoo.womlauncher.presentation.wizard.registration.RegistrationViewModel$1.onError(RegistrationViewModel.java:89)
at io.reactivex.internal.operators.single.SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver.onError(SingleFlatMap.java:116)
at io.reactivex.internal.observers.ResumeSingleObserver.onError(ResumeSingleObserver.java:51)
at io.reactivex.internal.disposables.EmptyDisposable.error(EmptyDisposable.java:78)
at io.reactivex.internal.operators.single.SingleError.subscribeActual(SingleError.java:42)
at io.reactivex.Single.subscribe(Single.java:3603)
out of this code -
public static<T> SingleTransformer<T,T> getSingleTransformer(){
return upstream -> upstream
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
GetHotelsList getHotelsList = new GetHotelsList(
AsyncTransformers.getSingleTransformer(), networkRepo);
getHotelsList.getHotels()
.map(hotels->
CollectionsUtil.mapList(hotels,
RegistrationMappers::mapHotelToPresentationHotel)
)
.flatMap((Function<List<HotelPresentation>, SingleSource<List<HotelPresentation>>>) hotelPresentations ->
Completable.timer(5,TimeUnit.SECONDS, Schedulers.io())
.andThen(Single.error(new Throwable()))
)
.subscribe(new SingleObserver<List<HotelPresentation>>() {
#Override
public void onSubscribe(Disposable d) {
addDisposable(d);
RegistrationState currentState = stateLiveData.getValue();
stateLiveData.setValue(currentState.newBuilder().setLoadingHotels(true).build());
}
#Override
public void onSuccess(List<HotelPresentation> hotelPresentations) {
RegistrationState currentState = stateLiveData.getValue();
stateLiveData.setValue(currentState.newBuilder().setHotelsList(hotelPresentations).setLoadingHotels(false).build());
}
#Override
public void onError(Throwable e) {
RegistrationState currentState = stateLiveData.getValue();
stateLiveData.setValue(currentState.newBuilder().setLoadingHotels(false).build());
}
});
and the debugger shown that onError called on RxSchedulerIoThread.

Android Room with RXJava2; onNext() of emitter is not properly triggered

I am switching from async tasks to rxjava2 and have some issues with my code tests.
I have a room table of elements that have a certain monetary amount. On a usercontrol that is called DisplayCurrentBudget, a sum of all amounts should be displayed. This number must refresh everytime a new element is inserted. I tackled the requirement in two ways, but both produce the same result: My code does not care if the database is updated, it only updates when the fragment is recreated (onCreateView).
My first attempt was this:
//RxJava2 Test
Observable<ItemS> ItemObservable = Observable.create( emitter -> {
try {
List<ItemS> movies = oStandardModel.getItemsVanilla();
for (ItemS movie : movies) {
emitter.onNext(movie);
}
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
DisposableObserver<ItemS> disposable = ItemObservable.
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribeWith(new DisposableObserver<ItemS>() {
public List<ItemS> BadFeelingAboutThis = new ArrayList<ItemS>();
#Override
public void onNext(ItemS movie) {
// Access your Movie object here
BadFeelingAboutThis.add(movie);
}
#Override
public void onError(Throwable e) {
// Show the user that an error has occurred
}
#Override
public void onComplete() {
// Show the user that the operation is complete
oBinding.DisplayCurrentBudget.setText(Manager.GetBigSum(BadFeelingAboutThis).toString());
}
});
I already was uncomfortable with that code. My second attempt produces the exact same result:
Observable<BigDecimal> ItemObservable2 = Observable.create( emitter -> {
try {
BigDecimal mySum = oStandardModel.getWholeBudget();
emitter.onNext(mySum);
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
DisposableObserver<BigDecimal> disposable = ItemObservable2.
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribeWith(new DisposableObserver<BigDecimal>() {
#Override
public void onNext(BigDecimal sum) {
// Access your Movie object here
oBinding.DisplayCurrentBudget.setText(sum.toString());
}
#Override
public void onError(Throwable e) {
// Show the user that an error has occurred
}
#Override
public void onComplete() {
// Show the user that the operation is complete
}
});
Any obvious issues with my code?
Thanks for reading, much appreciate it!
Edit:
I was asked what Manager.GetBigSum does, it actually does not do much. It only adds BigDecimal-Values of an Item list.
public static BigDecimal GetBigSum(List<ItemS> ListP){
List<BigDecimal> bigDList = ListP.stream().map(ItemS::get_dAmount).collect(Collectors.toList());
return bigDList.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
Further, I simplified the query. But it still does not care about DB updates, only about fragment recreation:
Single.fromCallable(() -> oStandardModel.getItemsVanilla())
.map(Manager::GetBigSum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(e.toString())
);
Your rx logic has no error. That should be internal error in your getWholeBudget.
But why you write rx so complex?
For your case, you can just write:
Single.fromCallable(() -> oStandardModel.getItemsVanilla())
.map(Manager::GetBigSum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(sum.toString()),
e -> log.error(e));
I solved it this way:
oStandardModel.getItemJointCatLive().observe(this, new Observer<List<ItemJointCat>>() {
#Override
public void onChanged(#Nullable final List<ItemJointCat> oItemSP) {
Single.fromCallable(() -> oStandardModel.getWholeBudget())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(e.toString())
);
}
});
My mistake was that I assumed RXjava2 does not need an onchanged event...now i just use onchanged event of livedata observer to trigger a simple rxjava2 query.
Do you think there is anything wrong with that approach?

Why Shiro's SubjectCallable need invoke restore method?

SubjectCallable's call method:
public V call() throws Exception {
try {
threadState.bind();
return doCall(this.callable);
} finally {
threadState.restore();
}
}
1.bind method is necsssary, but restore is why?
public void bind() {
SecurityManager securityManager = this.securityManager;
if ( securityManager == null ) {
//try just in case the constructor didn't find one at the time:
securityManager = ThreadContext.getSecurityManager();
}
this.originalResources = ThreadContext.getResources();
ThreadContext.remove();
ThreadContext.bind(this.subject);
if (securityManager != null) {
ThreadContext.bind(securityManager);
}
}
public void restore() {
ThreadContext.remove();
if (!CollectionUtils.isEmpty(this.originalResources)) {
ThreadContext.setResources(this.originalResources);
}
}
2.originalResources is use to do ? each time enter the AbstractShiroFilter will create a new subject and invoke it's execute method, the originalResources seems useless.
General thread health. You need to clean up resource in case the thread is re-used (very common). And it would help with garbage collection too.
Do you ever go hiking? Leave no trace ;)

compose with vertx for sequential code

I have two operations step_1() and step_2() and want to execute step_2() AFTER step_1().
With normal java this would be:
step_1();
step_2();
With vertx I have to use vertx-compose(). Am I right?
According to https://groups.google.com/forum/#!topic/vertx/FuvlPLpoGOA, I dont need Futures for sequential code.
"If you want to do each request sequencially you dont need futures."
So how can I do that without using futures?
I dont know, if this matters: My Vertx from which this code is executed is a "Worker"-Verticle.
#Override
public void start(Future<Void> fut) throws IOException {
Future<Void> step_1 = Future.future();
step_1.compose(res -> {
// If the future succeeded
Future<Void> step_2 = step_1();
step_2.compose(res2 -> {
step_2();
}, Future.future().setHandler(handler -> {
// If the future failed
}));
//I dont need that
}, Future.future().setHandler(handler -> {
// If the future failed
}));
}
public void step_1(){
..
}
public void step_2(){
..
}
Is this the right and shortest (!) way?
Below is an example of chaining of Future, I have made the example very trivial nonetheless it showcases the concept.
#RunWith(VertxUnitRunner.class)
public class Chaining {
private Vertx vertx = Vertx.vertx();
#Test
public void futures_chaining(TestContext context) throws Exception {
Async async = context.async();
firstOperation()
.compose((outcome) -> {
System.out.println(outcome);
return secondOperation();
})
.compose(outcome -> {
System.out.println(outcome);
/*
For stopping unit test we are returning this future
for production use-case this would be Future.succeededFuture
or Future.failedFuture depending on your method outcomes
*/
return Future.future(handle -> async.complete());
});
}
private Future<String> firstOperation() {
Future<String> future = Future.future();
vertx.setTimer(1000, delay -> future.complete("First Operation Complete"));
return future;
}
private Future<String> secondOperation() {
Future<String> future = Future.future();
vertx.setTimer(1000, delay -> future.complete("Second Operation Complete"));
return future;
}
}
"If you want to do each request sequencially you dont need futures."
No, it's not. In asynchronous frameworks like Vert.x, input/output operations are non-blocking. It means, that if you call few asynchronous operations, they'll start working simultaneously. And if you want to do few requests sequentially, then you should use futures or callbacks to execute new request only after previous one finished successfully.
Check this code with futures, newer version with RxJava 2 and article about project.
#Override
public Future<Optional<Todo>> getCertain(String todoID) {
Future<Optional<Todo>> result = Future.future();
redis.hget(Constants.REDIS_TODO_KEY, todoID, res -> {
if (res.succeeded()) {
result.complete(Optional.ofNullable(
res.result() == null ? null : new Todo(res.result())));
} else
result.fail(res.cause());
});
return result;
}
#Override
public Future<Todo> update(String todoId, Todo newTodo) {
return this.getCertain(todoId).compose(old -> {
if (old.isPresent()) {
Todo fnTodo = old.get().merge(newTodo);
return this.insert(fnTodo)
.map(r -> r ? fnTodo : null);
} else {
return Future.succeededFuture();
}
});
}
RxJava exists specifically to compose async events: http://vertx.io/docs/vertx-rx/java/
Assuming both step_1() and step_1() aren't designed to return results (i.e. they effectively return void) then you could change them to return Observable or Single and chain them together similar to this:
step_1().doOnSuccess(this::step_2()).subscribe(/* control resumes here */);
RxJava (or rather, reactive programming in general) takes a little bit to wrap your head around it, but I would strongly recommend using it if you're planning to chain together async operations.
Pass step_2 as argument to step_1
#Override
public void start(Future<Void> fut) throws IOException {
step_1(step_2);
}
private void step_1(Runnable function){
someAsynccall("some-arg", response -> {
function.run();
}).end();
}
private void step_2(){
// do something
}