/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.processor.strategy;
import static java.util.Objects.requireNonNull;
import static org.mule.runtime.core.api.processor.ReactiveProcessor.ProcessingType.BLOCKING;
import static org.mule.runtime.core.api.processor.ReactiveProcessor.ProcessingType.CPU_INTENSIVE;
import static org.mule.runtime.core.api.processor.ReactiveProcessor.ProcessingType.CPU_LITE;
import static reactor.core.publisher.Flux.from;
import static reactor.core.scheduler.Schedulers.fromExecutorService;
import org.mule.runtime.api.exception.MuleException;
import org.mule.runtime.api.lifecycle.Startable;
import org.mule.runtime.api.lifecycle.Stoppable;
import org.mule.runtime.api.scheduler.Scheduler;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.processor.ReactiveProcessor;
import org.mule.runtime.core.api.processor.ReactiveProcessor.ProcessingType;
import org.mule.runtime.core.api.processor.strategy.ProcessingStrategy;
import org.mule.runtime.core.api.scheduler.SchedulerService;
import java.util.function.Supplier;
/**
* Creates {@link ReactorProcessingStrategy} instance that use the {@link SchedulerService#cpuLightScheduler()} to process all
* incoming events. In contrast to the {@link ReactorProcessingStrategy} the proactor pattern treats
* {@link ProcessingType#CPU_INTENSIVE} and {@link ProcessingType#BLOCKING} processors differently and schedules there execution
* on dedicated {@link SchedulerService#cpuIntensiveScheduler()} and {@link SchedulerService#ioScheduler()} ()} schedulers.
* <p/>
* This processing strategy is not suitable for transactional flows and will fail if used with an active transaction.
*
* @since 4.0
*/
public class ProactorProcessingStrategyFactory extends ReactorProcessingStrategyFactory {
@Override
public ProcessingStrategy create(MuleContext muleContext, String schedulersNamePrefix) {
return new ProactorProcessingStrategy(() -> muleContext.getSchedulerService()
.cpuLightScheduler(muleContext.getSchedulerBaseConfig().withName(schedulersNamePrefix + "." + CPU_LITE.name())
.withMaxConcurrentTasks(getMaxConcurrency())),
() -> muleContext.getSchedulerService()
.ioScheduler(muleContext.getSchedulerBaseConfig()
.withName(schedulersNamePrefix + "." + BLOCKING.name())
.withMaxConcurrentTasks(getMaxConcurrency())),
() -> muleContext.getSchedulerService()
.cpuIntensiveScheduler(muleContext.getSchedulerBaseConfig()
.withName(schedulersNamePrefix + "." + CPU_INTENSIVE.name())
.withMaxConcurrentTasks(getMaxConcurrency())));
}
static class ProactorProcessingStrategy extends ReactorProcessingStrategy implements Startable, Stoppable {
private final Supplier<Scheduler> blockingSchedulerSupplier;
private final Supplier<Scheduler> cpuIntensiveSchedulerSupplier;
private Scheduler blockingScheduler;
private Scheduler cpuIntensiveScheduler;
public ProactorProcessingStrategy(Supplier<Scheduler> cpuLightSchedulerSupplier,
Supplier<Scheduler> blockingSchedulerSupplier,
Supplier<Scheduler> cpuIntensiveSchedulerSupplier) {
super(cpuLightSchedulerSupplier);
this.blockingSchedulerSupplier = requireNonNull(blockingSchedulerSupplier);
this.cpuIntensiveSchedulerSupplier = requireNonNull(cpuIntensiveSchedulerSupplier);
}
@Override
public void start() throws MuleException {
super.start();
this.blockingScheduler = blockingSchedulerSupplier.get();
this.cpuIntensiveScheduler = cpuIntensiveSchedulerSupplier.get();
}
@Override
public void stop() throws MuleException {
if (blockingScheduler != null) {
blockingScheduler.stop();
}
if (cpuIntensiveScheduler != null) {
cpuIntensiveScheduler.stop();
}
super.stop();
}
@Override
public ReactiveProcessor onProcessor(ReactiveProcessor processor) {
if (processor.getProcessingType() == BLOCKING) {
return proactor(processor, blockingScheduler);
} else if (processor.getProcessingType() == CPU_INTENSIVE) {
return proactor(processor, cpuIntensiveScheduler);
} else {
return super.onProcessor(processor);
}
}
private ReactiveProcessor proactor(ReactiveProcessor processor, Scheduler scheduler) {
return publisher -> from(publisher).publishOn(fromExecutorService(decorateScheduler(scheduler)))
.transform(processor).publishOn(fromExecutorService(decorateScheduler(getCpuLightScheduler())));
}
public Scheduler getBlockingScheduler() {
return blockingScheduler;
}
public Scheduler getCpuIntensiveScheduler() {
return cpuIntensiveScheduler;
}
}
}