toCompletableFuture() stucks for asynchronous cache - asynchronous

Hello there I am trying to force a promise to end to get the result from it but it just stucks on loading.
public class CacheController extends Controller {
private AsyncCacheApi cache;
public Result cache()
{
String test = "nice";
cache.set("item.key", test, 15);
Customer user = new Customer("Ana", 12);
CompletionStage<Done> result = cache.set(user.getName(), user);
block(result);
return ok("Cached");
}
public Result checkCache() throws Exception
{
Logger.info("start");
//CompletionStage<String> news = cache.get("item.key");
//news.thenRun(() -> System.out.println("works"));
CompletionStage<Customer> result = cache.get("Ana");
Logger.info("step 1");
Logger.info(cache.get("Ana").toString());
Logger.info("Step 2");
Customer c = block(result);
Logger.info("Step 3 " + c.getName());
//result.thenRun(() -> setUser(result)).thenRun(() -> Logger.info(user.getName() + " " + user.getAge()));
return ok("cancan");
}
private <T> T block(CompletionStage<T> stage) {
try {
return stage.toCompletableFuture().get();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
When trying to load the page it gets stuck after step2 at line 56: Customer c = block(result); by my guesses
Any ideas to fix it?

#Codrin
I had the same problem. But, see https://www.playframework.com/documentation/2.6.x/JavaCache#Setting-the-execution-context
By default, all Ehcache operations are blocking, and async implementations will block threads in the default execution context.
Maybe CompletableFuture.get() gets stuck because it is executed in the same thread with the caller.
Referring to the linked page, I added snippet below to my application.conf and it worked.
play.cache.dispatcher = "contexts.blockingCacheDispatcher"
contexts {
blockingCacheDispatcher {
fork-join-executor {
parallelism-factor = 3.0
}
}
}

Related

Multiple chained API calls to fetch data, but doOnNext of PublishSubject is never reached

I have a problem to understand a chained "RXJava-Retrofit" API call. I got inspired by this and implement this class named ObservationLoader to load the data from the API bucket per bucket. When the end of data is reached the API sends a endOfRecords=true:
public Observable<PageObject<Observation>> getAllObservationDataByRegion(long taxonKey,
String regionId) {
final PublishSubject<PageObject<Observation>> subject = PublishSubject.create();
return subject.doOnSubscribe(disposable -> {
this.getData(taxonKey, regionId, 0).subscribe(subject);
})
.doOnNext(observationPageObject -> {
if (observationPageObject.isEndOfRecords()) {
// -> list is completely loaded
subject.onComplete();
} else {
int nextOffset = observationPageObject.getOffset() + 1;
this.getData(taxonKey, regionId, null, nextOffset).subscribe(subject);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
private Observable<PageObject<Observation>> getData(long id,
String regionId,
int offset) {
// Get your API response value
return this.api.getObservations(id, regionId, ObservationLoader.PAGE_LIMIT, offset);
}
In my Android fragment HomeFragment I subscribe to the ObservationLoader:
ObservationLoader loader = new ObservationLoader(this.getApi());
Observable<PageObject<Observation>> observable = loader
.getAllObservationDataByRegion(this.getSelectedSpecies(), this.getSelectedRegion());
observable.subscribe(new Observer<PageObject<Observation>>() {
#Override
public void onSubscribe(Disposable d) {
Log.i(TAG, "ON_SUBSCRIBE");
}
#Override
public void onNext(PageObject<Observation> observationPageObject) {
Log.i(TAG, "ON_NEXT");
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "ERROR = " + e.getMessage());
}
#Override
public void onComplete() {
Log.i(TAG, "COMPLETED");
}
});
I can see that the onSubscribe() and doOnSubscribe() are called and even the getData() is reached. I assume the API is responding correctly (a previous attempt attempt with recursion worked fine). But I never reached the doOnNext function. The observer goes straight to onComplete() and no data is received. What could be the reason?
When doOnSubscribe runs, the doesn't see any consumers yet so if getData is synchronous, there won't be any first results to trigger further results. Also if getData ends, it will complete the setup so the next getData call in doOnNext will push to an already terminated subject, ingoring all data.
You'll need a differently organized feedback loop:
// we loop back the nextOffset, in a thread-safe manner
Subject<Integer> subject = PublishSubject.<Integer>create()
.toSerialized();
// bootstrap with 0 and keep open for more offsets
subject.mergeWith(Observable.just(0))
// get the data for the current offset
.concatMap(nextOffset -> getData(taxonKey, regionId, nextOffset)
.subscribeOn(Schedulers.io())
)
// if the response is end of records, stop
.takeWhile(observationPageObject -> !observationPageObject.isEndOfRecords())
// otherwise not end of records, feedback the new offset
.doOnNext(observationPageObject ->
subject.onNext(observationPageObject.getOffset() + 1)
)
// get the data on the main thread
.observeOn(AndroidSchedulers.mainThread());

How do I handle AX timeouts where the operation continues on? Abort not working?

I have a custom AX service operation that can take 5+ minutes to complete and I'm trying to figure out how to abort it from my .NET application, but aborting the client doesn't seem to do anything?
The problem is if I call the operation and the service times out, the AX operation continues on until completion, so I lose visibility to the results (success/failure). An example being a long-running posting operation where I don't know if it posted successfully or not.
I've created a simple demo app where I can't seem to get the operation to abort. In the below code I just create a transaction (ttsbegin/ttscommit), insert into a table at start, sleep, insert into table at end.
Sample AX X++ Service Code:
[SysEntryPointAttribute(true)]
public str callAXTimeDelay(int _sleepSeconds)
{
Table1 table1;
ttsBegin;
table1.clear();
table1.SleepData = strFmt("STARTED: %1", DateTimeUtil::utcNow());
table1.insert();
ttsCommit;
sleep(_sleepSeconds * 1000);
ttsBegin;
table1.clear();
table1.SleepData = strFmt("COMPLETED: %1", DateTimeUtil::utcNow());
table1.insert();
ttsCommit;
return strFmt("COMPLETED: %1", DateTimeUtil::utcNow());
}
Then when I call it from .NET, the abort doesn't seem to work? Start/Complete records are still inserted into table1 even though the abort is called before the 15 seconds have completed?
Sample .NET code:
internal class Program
{
static void Main(string[] args)
{
new Program().Run();
Console.WriteLine("Ended, press any key to exit...");
Console.ReadKey();
}
public void Run()
{
AXServicesClient axClient15Sec = new AXServicesClient();
AXServicesClient axClient5sec = new AXServicesClient();
var job15sec = DoLongRunningCall(axClient15Sec, 15);
var job5sec = DoLongRunningCall(axClient5sec, 5);
try
{
var result = Task.Run(() => Task.WhenAny(job15sec, job5sec)).GetAwaiter().GetResult();
if (result == job15sec)
{
Console.WriteLine("job15sec finished first, aborting job5sec");
axClient5sec.Abort();
}
else if (result == job5sec)
{
// This code gets executed because the 5 second job completed and
// it tries to cancel the 15-sec job, but the table ends up with data!
Console.WriteLine("job5sec finished first, aborting job15sec");
axClient15Sec.Abort();
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
axClient15Sec.Abort();
axClient5sec.Abort();
}
axClient15Sec.Close();
axClient5sec.Close();
}
public async Task<string> DoLongRunningCall(AXServicesClient client, int seconds)
{
var result = await client.callAXTimeDelay(new CallContext
{
Company = "ABCD",
Language = "en-us"
}, seconds);
return result.response;
}
}

WebFlux returning http.okay vice http.notFound

New to WebFlux, reactive, and handlers. I've got things "working", but am not understanding why following code is returning "okay" with empty body, vice "not found".
Clarification: The issue-of-concern is in the final return statement of DemoPOJOHandler.getById(). The "short-circuit" code works as expected (i.e., returns "Bad Request" status), but the "switchIfEmpty" path of the final return statement does not appear to get exercised if a DemoPOJORepo.getById(int) returns Mono.empty().
(Note: I've hacked up a list-based "repo" to avoid dealing with database while figuring out handlers and http return types.)
Router implementation ("/v1" is a set of annotation based RESTful endpoints)...
#Configuration
public class DemoPOJORouter {
#Bean
public RouterFunction<ServerResponse> route(DemoPOJOHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoPOJO"), requestHandler::getAll)
.andRoute(RequestPredicates.GET("/DemoPOJO/{id}"), requestHandler::getById)
.andRoute(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
Handler implementation has been "stripped down" to only the code in question. I have a feeling that much of the style is "still imperative", but I've attempted to put the reactive stuff where it "makes the most sense".
If I supply a bad value on the URI (i.e., "foo"), then I get the http "bad request" returned. But, never seem to get the "not found" that should be generated by "switchIfEmpty" if a validly formatted int value is supplied, but it does not map to an entry in the repo.
#Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
private DemoPOJORepo repo = null;
public Mono<ServerResponse> getById(ServerRequest request) {
Mono<DemoPOJO> monoDemoPOJO = null;
Map<String, String> pathVariables = request.pathVariables();
int id = -1;
checkRepoRef(); // part of the list hack
// short-circuit if request doesn't contain id (should never happen)
if ((pathVariables == null)
|| (!pathVariables.containsKey(PATH_VAR_ID))) {
return ServerResponse.badRequest().build();
}
// short-circuit if bad id value
try {
id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
} catch(NumberFormatException e) {
return ServerResponse.badRequest().build();
}
// get entity by keyValue
monoDemoPOJO = repo.getById(id);
return monoDemoPOJO
.flatMap(demoPOJO -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.syncBody(demoPOJO)
.switchIfEmpty(ServerResponse.notFound().build()));
}
}
Hack of a list-based repo to avoid dealing with data/APIs while working on handlers and http return types.
// local hack to avoid a database for testing
public class DemoPOJORepo {
private static DemoPOJORepo fpRepo = null;
private static int NUM_ROWS = 100;
private Map<Integer, DemoPOJO> fooPOJOMap;
private DemoPOJORepo() {
initMap();
}
public static DemoPOJORepo getInstance() {
if (fpRepo == null) {
fpRepo = new DemoPOJORepo();
}
return fpRepo;
}
public Mono<DemoPOJO> getById(int id) {
Mono<DemoPOJO> monoDP;
if (fooPOJOMap.containsKey(id)) {
monoDP = Mono.just(fooPOJOMap.get(id));
} else {
monoDP = Mono.empty();
}
return monoDP;
}
private Mono<Void> initMap() {
fooPOJOMap = new TreeMap<Integer, DemoPOJO>();
int offset = -1;
for(int ndx=0; ndx<NUM_ROWS; ndx++) {
offset = ndx + 1;
fooPOJOMap.put(offset, new DemoPOJO(offset, "foo_" + offset, offset+100));
}
return Mono.empty();
}
}
Your brackets are in the wrong place causing the swithIfEmpy to apply to the ServerResponse.ok() publisher not the monoDemoPOJO, replace the return with this and it should work:
return monoDemoPOJO
.flatMap(demoPOJO -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).syncBody(demoPOJO))
.switchIfEmpty(ServerResponse.notFound().build());
As I can see the code is right. The response code is Bad request because you are trying to convert "foo" to Integer, and when it throws an exception you are returning a Bad request response, so I think it works perfectly fine.
If you use an Integer id that is not present in your database then the answer must be a not found response

JavaFX, Is there any callback for Platform.runlater()?

My application adds multiple Runnable on FX thread, by calling Platform.runlater method, then, I want to do some calculations only when there is no additional Runnable is in the FX Platform queue.
But I don't know the right way, is there any event or callback mechanism to get the right time?
Currently I force the application thread to sleep randomly MILLISECONDS.
This is a bad idea from the start since you do not know what other code uses Platform.runLater. Also you should not rely on such implementation details; for all you know the queue could never be empty.
However you could post those Runnables using a custom class that keeps track of the number of Runnables and notifies you when all are done:
public class UpdateHandler {
private final AtomicInteger count;
private final Runnable completionHandler;
public UpdateHandler(Runnable completionHandler, Runnable... initialTasks) {
if (completionHandler == null || Stream.of(initialTasks).anyMatch(Objects::isNull)) {
throw new IllegalArgumentException();
}
count = new AtomicInteger(initialTasks.length);
this.completionHandler = completionHandler;
for (Runnable r : initialTasks) {
startTask(r);
}
}
private void startTask(Runnable runnable) {
Platform.runLater(() -> {
runnable.run();
if (count.decrementAndGet() == 0) {
completionHandler.run();
}
});
}
public void Runnable runLater(Runnable runnable) {
if (runnable == null) {
throw new IllegalArgumentException();
}
count.incrementAndGet();
startTask(runnable);
}
}

rxjava - Combine onerror and timout handling

I will start with what I want to achieve.
I want to call a method that returns an Observabe.
I do not know if the called method handles exceptions and timeouts
I want to combine observables in my call (merge/zip etc)
if one method fails, I want the answers from the methods that succeeded -
I don't want to break the flow.
In case of exception, I am capable of handling it and continuing with the flow,
but when I try to add timeoutmanagement I fail.
Here is my code
public static void main(String[] args) {
createObservables(false, true); // stalls for timeout
zip();
}
private static void createObservables(final boolean throwException,
final boolean stall) {
obs1 = Observable.just(1);
obs1 = obs1.map(new Func1<Integer, Integer>() {
#Override public Integer call(Integer integer) {
int i = 0;
if (throwException)
getObj().equals("");
if (stall)
zzz(10);
return ++integer;
}
});
obs2 = Observable.just(111);
}
private static void zip() {
System.out.println("**Zip**");
obs1 = obs1.onErrorReturn(new Func1<Throwable, Integer>() {
#Override public Integer call(Throwable throwable) {
return 999;
}
});
obs1 = obs1.timeout(5, TimeUnit.SECONDS);
Observable.zip(obs1, obs2, new Func2<Integer, Integer, ArrayList<Integer>>() {
#Override
public ArrayList<Integer> call(Integer integer1, Integer integer2) {
ArrayList<Integer> integers = new ArrayList<Integer>();
integers.add(integer1);
integers.add(integer2);
return integers;
}
}).subscribe(new Observer<Object>() {....}
);
}
Now, when I call
createObservables(false , false); // no exceptions and timeouts
I get onNext - [2, 111].
then I call
createObservables(true, false); // throw exception in one method only
I get onNext - [999, 111] - which is what I want. Exception and the result from the second method.
But when I call
createObservables(false, true); // stall on timeout
I get only onError.
But I want to get the other method answer.
Thanks.
Try creating an observable for your timeout value, in this case you want the same value as your error case:
Observable obs1Timeout = Observable.just(999);
Then in your timeout policy give it this observable as the fallback to use in the case of a timeout:
obs1 = obs1.timeout(5, TimeUnit.SECONDS, obs1Timeout);

Resources