/** * Create a {@link Scheduler} which uses a backing {@link Executor} to schedule * Runnables for async operators. * * <p>Tasks scheduled with workers of this Scheduler are not guaranteed to run in FIFO * order and strictly non-concurrently. * If FIFO order is desired, use trampoline parameter of {@link Schedulers#fromExecutor(Executor, boolean)} * * @param executor an {@link Executor} * * @return a new {@link Scheduler} */ public static Scheduler fromExecutor(Executor executor) { return fromExecutor(executor, false); }
.publishOn(fromExecutor(executor)) .subscribe(assertSubscriber);
/** * Creates a new SubmissionPublisher using the given Executor for * async delivery to subscribers, with the given maximum buffer size * for each subscriber. * * @param executor the executor to use for async delivery, * supporting creation of at least one independent thread * @param maxBufferCapacity the maximum capacity for each * subscriber's buffer * @throws IllegalArgumentException if maxBufferCapacity not * positive */ public SubmissionPublisher(Executor executor, int maxBufferCapacity){ this(Schedulers.fromExecutor(executor), maxBufferCapacity); }
.publishOn(fromExecutor(executor)) .subscribe(assertSubscriber);
@Override protected Scheduler scheduler() { return Schedulers.fromExecutor(Runnable::run); }
.publishOn(fromExecutor(executor)) .subscribe(assertSubscriber);
@Override protected Scheduler scheduler() { return Schedulers.fromExecutor(Runnable::run, true); }
.publishOn(fromExecutor(executor)) .subscribe(assertSubscriber);
@Override protected Scheduler scheduler() { return Schedulers.fromExecutor(Executors.newSingleThreadScheduledExecutor()); }
ArmeriaServerHttpRequest(ServiceRequestContext ctx, HttpRequest req, DataBufferFactoryWrapper<?> factoryWrapper) { super(URI.create(requireNonNull(req, "req").path()), null, fromArmeriaHttpHeaders(req.headers())); this.ctx = requireNonNull(ctx, "ctx"); this.req = req; body = Flux.from(req).cast(HttpData.class).map(factoryWrapper::toDataBuffer) // Guarantee that the context is accessible from a controller method // when a user specify @RequestBody in order to convert a request body into an object. .publishOn(Schedulers.fromExecutor(ctx.contextAwareExecutor())); }
private Mono<Void> write(Flux<? extends DataBuffer> publisher) { return Mono.defer(() -> { final HttpResponse response = HttpResponse.of( Flux.concat(Mono.just(headers), publisher.map(factoryWrapper::toHttpData)) // Publish the response stream on the event loop in order to avoid the possibility of // calling subscription.request() from multiple threads while publishing messages // with onNext signals or starting the subscription with onSubscribe signal. .publishOn(Schedulers.fromExecutor(ctx.eventLoop()))); future.complete(response); return Mono.fromFuture(response.completionFuture()); }); }
@Test(timeout = 5000) public void executorThreadCheck() throws Exception{ ExecutorService es = Executors.newSingleThreadExecutor(); Scheduler s = Schedulers.fromExecutor(es::execute); try { Scheduler.Worker w = s.createWorker(); Thread currentThread = Thread.currentThread(); AtomicReference<Thread> taskThread = new AtomicReference<>(currentThread); CountDownLatch latch = new CountDownLatch(1); w.schedule(() -> { taskThread.set(Thread.currentThread()); latch.countDown(); }); latch.await(); assertThat(taskThread.get()).isNotEqualTo(currentThread); } finally { s.dispose(); es.shutdownNow(); } }
@Test(timeout = 5000) public void executorThreadCheck2() throws Exception{ ExecutorService es = Executors.newSingleThreadExecutor(); Scheduler s = Schedulers.fromExecutor(es::execute, true); try { Scheduler.Worker w = s.createWorker(); Thread currentThread = Thread.currentThread(); AtomicReference<Thread> taskThread = new AtomicReference<>(currentThread); CountDownLatch latch = new CountDownLatch(1); w.schedule(() -> { taskThread.set(Thread.currentThread()); latch.countDown(); }); latch.await(); assertThat(taskThread.get()).isNotEqualTo(currentThread); } finally { s.dispose(); es.shutdownNow(); } }
.publishOn(fromExecutor(executor)) .block(); Assert.fail("Bubbling RejectedExecutionException expected");
.publishOn(fromExecutor(executor)) .block(); Assert.fail("Bubbling RejectedExecutionException expected");
@Test public void timeoutDropWhenNoCancelWithoutFallback() { for (int i = 0; i < 50; i++) { StepVerifier.withVirtualTime( () -> Flux.just("cat") .delaySubscription(Duration.ofMillis(3)) // We cancel on another scheduler that won't do anything to force it to act like // the event is already in flight .cancelOn(Schedulers.fromExecutor(r -> {})) .timeout(Duration.ofMillis(2)) ) .thenAwait(Duration.ofSeconds(5)) .expectError(TimeoutException.class) .verify(); } }
@Test public void timeoutDropWhenNoCancelWithFallback() { for (int i = 0; i < 50; i++) { StepVerifier.withVirtualTime( () -> Flux.just("cat") .delaySubscription(Duration.ofMillis(3)) // We cancel on another scheduler that won't do anything to force it to act like // the event is already in flight .cancelOn(Schedulers.fromExecutor(r -> {})) .timeout(Duration.ofMillis(2), Flux.just("dog").delayElements(Duration.ofMillis(5))) ) .thenAwait(Duration.ofSeconds(5)) .expectNext("dog") .expectComplete() .verify(); } }
@Test public void scanName() { Executor executor = new PlainExecutor(); Scheduler noTrampoline = Schedulers.fromExecutor(executor, false); Scheduler withTrampoline = Schedulers.fromExecutor(executor, true); Scheduler.Worker workerNoTrampoline = noTrampoline.createWorker(); Scheduler.Worker workerWithTrampoline = withTrampoline.createWorker(); try { assertThat(Scannable.from(noTrampoline).scan(Scannable.Attr.NAME)) .as("noTrampoline") .isEqualTo("fromExecutor(\"plain\")"); assertThat(Scannable.from(withTrampoline).scan(Scannable.Attr.NAME)) .as("withTrampoline") .isEqualTo("fromExecutor(\"plain\",trampolining)"); assertThat(Scannable.from(workerNoTrampoline).scan(Scannable.Attr.NAME)) .as("workerNoTrampoline") .isEqualTo("fromExecutor(\"plain\").worker"); assertThat(Scannable.from(workerWithTrampoline).scan(Scannable.Attr.NAME)) .as("workerWithTrampoline") .isEqualTo("fromExecutor(\"plain\",trampolining).worker"); } finally { noTrampoline.dispose(); withTrampoline.dispose(); workerNoTrampoline.dispose(); workerWithTrampoline.dispose(); } }
eventBus = new DefaultEventBus(Schedulers.fromExecutor(eventExecutorGroup)); } else { eventBus = builder.eventBus;
return Arrays.asList( scenario(f -> f.publishOn(Schedulers.fromExecutor(d -> { throw exception(); })))