Last active
February 24, 2021 21:19
-
-
Save bion/66979b02e2ff93e0ba61a79baaf6376a to your computer and use it in GitHub Desktop.
Threading in Play
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See https://www.playframework.com/documentation/2.8.x/ThreadPools for more info | |
// | |
// Applicant-accessible code paths should never block on network I/O. | |
// If you use CompleteableFuture#join() be very careful it is not on an applicant-accessible code path. | |
class ThreadingDemo { | |
private final HttpExecutionContext httpExecutionContext; | |
private final DatabaseExecutionContext databaseExecutionContext; | |
private final DemoService demoService; | |
@Inject | |
ThreadingDemo(HttpExecutionContext httpExecutionContext, | |
DatabaseExecutionContext DatabaseExecutionContext, | |
DemoService demoService) { | |
this.httpExecutionContext = checkNotNull(httpExecutionContext); | |
this.databaseExecutionContext = checkNotNull(DatabaseExecutionContext); | |
this.demoService = checkNotNull(demoService); | |
} | |
// Code that makes synchronous calls to the database should always run on the database | |
// dispatcher thread pool i.e. DatabaseExecutionContext. | |
public CompletionStage<Applicant> databaseInteraction() { | |
return supplyAsync(() -> { | |
Applicant applicant = new Applicant(); | |
applicant.id = 1L; | |
applicant.refresh(); // synchronous DB call | |
return applicant; | |
}, databaseExecutionContext); | |
} | |
// Using HttpExecutionContext when resuming from an async call ensures that | |
// callbacks executed when the completion stage is redeemed have the correct ClassLoader | |
public CompletionStage<FinalResultType> singleAsyncDependency() { | |
return demoService.getDemoThing().thenApplyAsync((DemoThing demoThing) -> { | |
return new FinalResultType(demoThing); | |
}, httpExecutionContext.current()); | |
} | |
// When you want to do work that depends on multiple async calls that do not depend | |
// on eachother, use CompletableFuture.allOf | |
// This can allow the network I/O to run in parallel. | |
public CompletionStage<FinalResultType> multipleAsyncDependencies() { | |
// initiate async calls for the dependencies | |
CompletableFuture<Applicant> applicantCompletableFuture = databaseInteraction().toCompletableFuture(); | |
CompletableFuture<DemoThing> demoThingCompleteableFuture = demoService.getDemoThing().toCompletableFuture(); | |
CompletableFuture<OtherDemoThing> otherDemoThingCompleteableFuture = demoService.getOtherDemoThing().toCompletableFuture(); | |
// create a CompletionStage that completes when all dependencies have completed | |
return CompletableFuture.allOf(applicantCompletableFuture, demoThingCompleteableFuture, otherDemoThingCompleteableFuture) | |
// register a callback on the current execution context for when the depencies are ready | |
.thenApplyAsync( | |
() -> { | |
Applicant applicant = applicantCompletableFuture.join(); | |
DemoThing demoThing = demoThingCompleteableFuture.join(); | |
OtherDemoThing otherDemoThing = otherDemoThingCompleteableFuture.join(); | |
return new FinalResultType(applicant, demoThing, otherDemoThing); | |
}, | |
httpExecutionContext.current()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment