@Test public void simpleTest() throws Exception { final TopicProcessor<Integer> sink = TopicProcessor.<Integer>builder().name("topic").build(); final WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder().name("queue").build();
@Test(timeout = 5_000) public void testBufferSize1Shared() throws Exception { WorkQueueProcessor<String> broadcast = WorkQueueProcessor.<String>builder() .share(true) .name("share-name") .bufferSize(1) .autoCancel(true) .build(); int simultaneousSubscribers = 3000; CountDownLatch latch = new CountDownLatch(simultaneousSubscribers); Scheduler scheduler = Schedulers.single(); FluxSink<String> sink = broadcast.sink(); Flux<String> flux = broadcast.filter(Objects::nonNull) .publishOn(scheduler) .cache(1); for (int i = 0; i < simultaneousSubscribers; i++) { flux.subscribe(s -> latch.countDown()); } sink.next("data"); Assertions.assertThat(latch.await(4, TimeUnit.SECONDS)) .overridingErrorMessage("Data not received") .isTrue(); }
@Test(timeout = 5_000) public void testBufferSize1Created() throws Exception { WorkQueueProcessor<String> broadcast = WorkQueueProcessor.<String>builder() .share(true).name("share-name") .bufferSize(1) .autoCancel(true) .build(); int simultaneousSubscribers = 3000; CountDownLatch latch = new CountDownLatch(simultaneousSubscribers); Scheduler scheduler = Schedulers.single(); FluxSink<String> sink = broadcast.sink(); Flux<String> flux = broadcast.filter(Objects::nonNull) .publishOn(scheduler) .cache(1); for (int i = 0; i < simultaneousSubscribers; i++) { flux.subscribe(s -> latch.countDown()); } sink.next("data"); Assertions.assertThat(latch.await(4, TimeUnit.SECONDS)) .overridingErrorMessage("Data not received") .isTrue(); }
@Override public Processor<Long, Long> createIdentityProcessor(int bufferSize) { Flux<String> otherStream = Flux.just("test", "test2", "test3"); // System.out.println("Providing new downstream"); FluxProcessor<Long, Long> p = WorkQueueProcessor.<Long>builder().name("fluxion-raw-fork").bufferSize(bufferSize).build(); cumulated.set(0); cumulatedJoin.set(0); BiFunction<Long, String, Long> combinator = (t1, t2) -> t1; return FluxProcessor.wrap(p, p.groupBy(k -> k % 2 == 0) .flatMap(stream -> stream.scan((prev, next) -> next) .map(integer -> -integer) .filter(integer -> integer <= 0) .map(integer -> -integer) .bufferTimeout(1024, Duration.ofMillis(50)) .flatMap(Flux::fromIterable) .doOnNext(array -> cumulated.getAndIncrement()) .flatMap(i -> Flux.zip(Flux.just(i), otherStream, combinator))) .doOnNext(array -> cumulatedJoin.getAndIncrement()) .subscribeWith(TopicProcessor.<Long>builder().name("fluxion-raw-join").bufferSize(bufferSize).build()) .doOnError(Throwable::printStackTrace)); }
@Test public void testForceShutdownAfterShutdown() throws InterruptedException { WorkQueueProcessor<String> processor = WorkQueueProcessor.<String>builder() .name("processor").bufferSize(4) .waitStrategy(WaitStrategy.phasedOffLiteLock(200, 100, TimeUnit.MILLISECONDS)) //eliminate the waitstrategy diff .build(); Publisher<String> publisher = Flux.fromArray(new String[] { "1", "2", "3", "4", "5" }); publisher.subscribe(processor); AssertSubscriber<String> subscriber = AssertSubscriber.create(0); processor.subscribe(subscriber); subscriber.request(1); Thread.sleep(250); processor.shutdown(); assertFalse(processor.awaitAndShutdown(Duration.ofMillis(400))); processor.forceShutdown(); assertTrue(processor.awaitAndShutdown(Duration.ofMillis(400))); }
@Test public void testDefaultRequestTaskThreadName() { String mainName = "workQueueProcessorRequestTask"; String expectedName = mainName + "[request-task]"; WorkQueueProcessor<Object> processor = WorkQueueProcessor.builder().name(mainName).bufferSize(8).build(); processor.requestTask(Operators.cancelledSubscription()); Thread[] threads = new Thread[Thread.activeCount()]; Thread.enumerate(threads); //cleanup to avoid visibility in other tests processor.forceShutdown(); Condition<Thread> defaultRequestTaskThread = new Condition<>( thread -> thread != null && expectedName.equals(thread.getName()), "a thread named \"%s\"", expectedName); Assertions.assertThat(threads) .haveExactly(1, defaultRequestTaskThread); }
/** * Create a new shared WorkQueueProcessor using the passed buffer size, blockingWait * Strategy and auto-cancel. <p> A Shared Processor authorizes concurrent onNext calls * and is suited for multi-threaded publisher that will fan-in data. <p> A new Cached * ThreadExecutorPool will be implicitly created and will use the passed name to * qualify the created threads. * @param name Use a new Cached ExecutorService and assign this name to the created * threads * @param bufferSize A Backlog Size to mitigate slow subscribers * @param <E> Type of processed signals * @return a fresh processor */ public static <E> WorkQueueProcessor<E> share(String name, int bufferSize) { return WorkQueueProcessor.<E>builder().share(true).name(name).bufferSize(bufferSize).build(); }
@Test public void shareDefaultExecutorOverrideAll() { String name = "nameOverride"; int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .name(name) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, name, bufferSize, waitStrategy, autoCancel, null, null); }
@Test @Ignore public void test() throws Exception { processor = WorkQueueProcessor.builder().name("test-processor").bufferSize(RINGBUFFER_SIZE).build(); Flux .create((emitter) -> burstyProducer(emitter, PRODUCED_MESSAGES_COUNT, BURST_SIZE)) .onBackpressureDrop(this::incrementDroppedMessagesCounter) // .log("test", Level.INFO, SignalType.REQUEST) .subscribeWith(processor) .map(this::complicatedCalculation) .subscribe(this::logConsumedValue); waitForProducerFinish(); System.out.println("\n\nMax ringbuffer pending: " + maxRingBufferPending.get()); assertEquals(getDroppedMessagesCount(), 0, "Expect zero dropped messages"); }
@Test public void createDefaultExecutorOverrideAll() { String name = "nameOverride"; int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .name(name) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, name, bufferSize, waitStrategy, autoCancel, null, null); }
@Test(expected = IllegalArgumentException.class) public void failNullBufferSize() { WorkQueueProcessor.builder().name("test").bufferSize(0); }
/** * Create a new WorkQueueProcessor using the passed buffer size, blockingWait * Strategy and auto-cancel. <p> A new Cached ThreadExecutorPool will be implicitly * created and will use the passed name to qualify the created threads. * @param name Use a new Cached ExecutorService and assign this name to the created * threads * @param bufferSize A Backlog Size to mitigate slow subscribers * @param <E> Type of processed signals * @return a fresh processor */ public static <E> WorkQueueProcessor<E> create(String name, int bufferSize) { return WorkQueueProcessor.<E>builder().name(name).bufferSize(bufferSize).build(); }
@Test public void shareOverrideNameBufferSizeWaitStrategy() { String name = "nameOverride"; int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .name(name) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .build(); assertProcessor(processor, true, name, bufferSize, waitStrategy, null, null, null); }
@Test(expected = IllegalArgumentException.class) public void failNegativeBufferSize() { WorkQueueProcessor.builder().name("test").bufferSize(-1); }
@Test(expected = IllegalArgumentException.class) public void failNonPowerOfTwo() { WorkQueueProcessor.builder().name("test").bufferSize(3); }
@Test public void createOverrideName() { String name = "nameOverride"; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .name(name) .build(); assertProcessor(processor, false, name, null, null, null, null, null); }
@Test public void testWorkQueueProcessorGetters() { final int TEST_BUFFER_SIZE = 16; WorkQueueProcessor<Object> processor = WorkQueueProcessor.builder().name("testProcessor").bufferSize(TEST_BUFFER_SIZE).build(); assertEquals(TEST_BUFFER_SIZE, processor.getAvailableCapacity()); processor.onNext(new Object()); assertEquals(TEST_BUFFER_SIZE - 1, processor.getAvailableCapacity()); processor.awaitAndShutdown(); }
@Test public void createOverrideNameBufferSizeWaitStrategy() { String name = "nameOverride"; int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .name(name) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .build(); assertProcessor(processor, false, name, bufferSize, waitStrategy, null, null, null); }
@Test public void createOverrideNameBufferSizeAutoCancel() { String name = "nameOverride"; int bufferSize = 1024; boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .name(name) .bufferSize(bufferSize) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, name, bufferSize, null, autoCancel, null, null); }
@Override public Processor<Long, Long> createIdentityProcessor(int bufferSize) { return WorkQueueProcessor.<Long>builder() .name("workQueueProcessorVerification") .bufferSize(bufferSize) .build(); }