Skip to content

Commit

Permalink
perf($Quartz): customize Quartz thread pool by CPU core count
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnymillergh committed Sep 22, 2021
1 parent e6bf0e6 commit 601c4f1
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 8 deletions.
4 changes: 0 additions & 4 deletions auth-center/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,6 @@ spring:
isClustered: true
clusterCheckinInterval: 3000
useProperties: false
threadPool:
threadCount: 15
threadPriority: 5
class: org.quartz.simpl.SimpleThreadPool

feign:
httpclient:
Expand Down
4 changes: 0 additions & 4 deletions maf-mis/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ spring:
isClustered: true
clusterCheckinInterval: 3000
useProperties: false
threadPool:
threadCount: 15
threadPriority: 5
class: org.quartz.simpl.SimpleThreadPool

feign:
httpclient:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.quartz.QuartzProperties;
import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.Map;
import java.util.Optional;
import java.util.Properties;

/**
* Description: QuartzConfiguration, change description here.
Expand All @@ -22,6 +26,26 @@
@Slf4j
@ConditionalOnClass({Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class})
public class QuartzConfiguration {
private static final String THREAD_COUNT = "org.quartz.threadPool.threadCount";

@Bean
public SchedulerFactoryBeanCustomizer threadPoolCustomizer(QuartzProperties quartzProperties) {
return schedulerFactoryBean -> {
val cpuCoreCount = Runtime.getRuntime().availableProcessors();
val threadCount = String.valueOf(cpuCoreCount * 2);
quartzProperties.getProperties().put(THREAD_COUNT, threadCount);
log.warn("Quartz thread pool enhanced by current cpuCoreCount: {}, threadCount: {}", cpuCoreCount,
threadCount);
schedulerFactoryBean.setQuartzProperties(this.asProperties(quartzProperties.getProperties()));
};
}

private Properties asProperties(Map<String, String> source) {
val properties = new Properties();
properties.putAll(source);
return properties;
}

@Bean
public GreetingQuartzJobBean greetingQuartzJobBean(MafProjectProperty mafProjectProperty) {
log.warn("Initial bean: '{}'", GreetingQuartzJobBean.class.getSimpleName());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.jmsoftware.maf.springcloudstarter.quartz;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.quartz.QuartzProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

/**
* <p>QuartzSchedulerPostProcessor is to enhance Quartz thread pool by CPU core count.</p>
* <p><a href='https://en.wikipedia.org/wiki/Hyper-threading#Overview'>Hyper-threading</a>
* works by duplicating certain sections of the processor—those that store the
* <a href='https://en.wikipedia.org/wiki/Architectural_state'>architectural state</a>
* —but not duplicating the main <a href='https://en.wikipedia.org/wiki/Execution_unit'>execution resources</a>
* . This allows a hyper-threading processor to appear as the usual &quot;physical&quot; processor and an extra
* &quot;<a href='https://en.wikipedia.org/wiki/Virtualization'>logical</a>
* &quot; processor to the host operating system (HTT-unaware operating systems see two &quot;physical&quot;
* processors), allowing the operating system to schedule two threads or processes simultaneously and appropriately.</p>
*
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 8/25/2021 11:27 AM
**/
@Slf4j
@RequiredArgsConstructor
public class QuartzSchedulerPostProcessor implements BeanPostProcessor, DisposableBean {
private static final String THREAD_COUNT = "org.quartz.threadPool.threadCount";
private final ApplicationContext applicationContext;
private final QuartzProperties quartzProperties;
private int initializedBeanCounter = 0;

@Nullable
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
this.initializedBeanCounter++;
if (bean instanceof SchedulerFactoryBean) {
this.enhanceThreadPool();
}
return bean;
}

private void enhanceThreadPool() {
log.info("Spring initialized {} beans previously, beanDefinitionCount: {}", this.initializedBeanCounter,
this.applicationContext.getBeanDefinitionCount());
val cpuCoreCount = Runtime.getRuntime().availableProcessors();
val threadCount = String.valueOf(cpuCoreCount * 2 + 1);
this.quartzProperties.getProperties().put(THREAD_COUNT, threadCount);
log.warn("Quartz thread pool enhanced by current cpuCoreCount: {}, threadCount: {}", cpuCoreCount,
threadCount);
this.applicationContext.getAutowireCapableBeanFactory().destroyBean(this);
}

@Override
public void destroy() {
log.warn("Destroyed bean {}", this.getClass().getSimpleName());
}
}

0 comments on commit 601c4f1

Please sign in to comment.