java - CompletableFuture#whenComplete not called if thenApply is used -


i have following code (resulting my previous question) schedules task on remote server, , polls completion using scheduledexecutorservice#scheduleatfixedrate. once task complete, downloads result. want return future caller can decide when , how long block, , give them option cancel task.

my problem if client cancels future returned download method, whencomplete block doesn't execute. if remove thenapply does. it's obvious i'm misunderstanding future composition... should change?

public future<object> download(something something) {     string jobid = schedule(something);     completablefuture<string> job = pollforcompletion(jobid);     return job.thenapply(this::downloadresult); }  private completablefuture<string> pollforcompletion(string jobid) {     scheduledexecutorservice executor = executors.newsinglethreadscheduledexecutor();     completablefuture<string> completionfuture = new completablefuture<>();      scheduledfuture<?> checkfuture = executor.scheduleatfixedrate(() -> {                        if (pollremoteserver(jobid).equals("complete")) {                 completionfuture.complete(jobid);             }     }, 0, 10, timeunit.seconds);     completionfuture                             .whencomplete((result, thrown) -> {                 system.out.println("xxxxxxxxxxx"); //never happens unless thenapply removed                 checkfuture.cancel(true);                 executor.shutdown();             });     return completionfuture; } 

on same note, if do:

return completionfuture.whencomplete(...) 

instead of

completionfuture.whencomplete(...); return completionfuture; 

whencomplete never executes. seems counterintuitive me. shouldn't logically future returned whencomplete 1 should hold on to?

edit:

i changed code explicitly back-propagate cancellation. it's abhorrent , unreadable, works , couldn't find better way:

public future<object> download(something something) throws chartdatagenexception, exception {         string jobid = schedule(report);         completablefuture<string> job = pollforcompletion(jobid);         completablefuture<object> resulting = job.thenapply(this::download);         resulting.whencomplete((result, thrown) -> {             if (resulting.iscancelled()) { //the check not necessary, communicates intent better                 job.cancel(true);             }         });         return resulting; } 

your structure follows:

           ┌──────────────────┐            │ completionfuture |            └──────────────────┘              ↓              ↓   ┌──────────────┐      ┌───────────┐   │ whencomplete |      │ thenapply |   └──────────────┘      └───────────┘ 

so when cancel thenapply future, original completionfuture object remains unaffected doesn’t depend on thenapply stage. if, however, don’t chain thenapply stage, you’re returning original completionfuture instance , canceling stage causes cancellation of dependent stages, causing whencomplete action executed immediately.

but when thenapply stage cancelled, completionfuture still may completed when pollremoteserver(jobid).equals("complete") condition fulfilled, polling doesn’t stop. don’t know relationship of jobid = schedule(something) , pollremoteserver(jobid). if application state changes in way condition can never fulfilled after canceling download, future never complete…


regarding last question, future “the 1 should hold on to?”, there no requirement have linear chain of futures, in fact, while convenience methods of completablefuture make easy create such chain, more often, it’s least useful thing do, write block of code, if have linear dependency. model of chaining 2 independent stages right, cancellation doesn’t work through it, wouldn’t work through linear chain either.

if want able cancel source stage, need reference it, if want able result of dependent stage, you’ll need reference stage too.


Comments

Popular posts from this blog

python - How to insert QWidgets in the middle of a Layout? -

python - serve multiple gunicorn django instances under nginx ubuntu -

module - Prestashop displayPaymentReturn hook url -