public abstract class Blocking extends Object
Modifier and Type | Method and Description |
---|---|
static void |
exec(Block block) |
static <T> Promise<T> |
get(Factory<T> factory)
Performs a blocking operation on a separate thread, returning a promise for its value.
|
static <T> T |
on(Promise<T> promise)
Blocks execution waiting for this promise to complete and returns the promised value.
|
static Operation |
op(Block block) |
public static <T> Promise<T> get(Factory<T> factory)
This method should be used to perform blocking IO, or to perform any operation that synchronously waits for something to happen. The given factory function will be executed on a thread from a special pool for such operations (i.e. not a thread from the main compute event loop).
The operation should do as little computation as possible. It should just perform the blocking operation and immediately return the result. Performing computation during the operation will degrade performance.
T
- the type of value created by the operationfactory
- the operation that blockspublic static <T> T on(Promise<T> promise) throws Exception
This method allows the use of asynchronous API, by synchronous API. This may occur when integrating with other libraries that are not asynchronous. The following example simulates using a library that takes a callback that is expected to produce a value synchronously, but where the production of the value is actually asynchronous.
import ratpack.test.exec.ExecHarness;
import ratpack.exec.ExecResult;
import ratpack.exec.Blocking;
import ratpack.exec.Promise;
import ratpack.func.Factory;
import static org.junit.Assert.assertEquals;
public class Example {
static <T> T produceSync(Factory<? extends T> factory) throws Exception {
return factory.create();
}
public static void main(String... args) throws Exception {
ExecResult<String> result = ExecHarness.yieldSingle(e ->
Blocking.get(() ->
produceSync(() ->
Blocking.on(Promise.value("foo")) // block and wait for the promised value
)
)
);
assertEquals("foo", result.getValue());
}
}
Important: this method can only be used inside a Blocking
function.
That is, it can only be used from a Ratpack managed blocking thread.
If it is called on a non Ratpack managed blocking thread it will immediately throw an ExecutionException
.
When this method is called, the promise will be subscribed to on a compute thread while the blocking thread waits.
When the promised value has been produced, and the compute thread segment has completed, the value will be returned
allowing execution to continue on the blocking thread.
The following example visualises this flow by capturing the sequence of events via an ExecInterceptor
.
import ratpack.test.exec.ExecHarness;
import ratpack.exec.Blocking;
import ratpack.exec.Promise;
import ratpack.exec.ExecResult;
import ratpack.exec.ExecInterceptor;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
public class Example {
public static void main(String... args) throws Exception {
List<String> events = new ArrayList<>();
ExecHarness.yieldSingle(
r -> r.add(ExecInterceptor.class, (execution, execType, continuation) -> {
events.add(execType + "-start");
try {
continuation.execute();
} finally {
events.add(execType + "-stop");
}
}),
e -> Blocking.get(() -> Blocking.on(Promise.value("foo")))
);
List<String> actualEvents = Arrays.asList(
"COMPUTE-start",
"COMPUTE-stop",
"BLOCKING-start",
"COMPUTE-start",
"COMPUTE-stop",
"BLOCKING-stop",
"COMPUTE-start",
"COMPUTE-stop"
);
assertEquals(actualEvents, events);
}
}
T
- the type of value returned by the promisepromise
- the promise to block onExecutionException
- if not called on a Ratpack managed blocking threadException
- any thrown while producing the valuepublic static void exec(Block block)