《Flowable文档大全》
When reading the async executor design section, it becomes clear that the architecture is inspired by message queues. The async executor is designed in such a way that a message queue can easily be used to take over the job of the thread pool and the handling of async jobs.
Benchmarks have shown that using a message queue is superior, throughput-wise, to the thread pool-backed async executor. However, it does come with an extra architectural component, which of course makes setup, maintenance and monitoring more complex. For many users, the performance of the thread pool-backed async executor is more than sufficient. It is nice to know however, that there is an alternative if the required performance grows.
阅读异步执行器设计部分时,可以清楚地看到,该体系结构受到了消息队列的启发。异步执行器的设计方式使消息队列可以轻松地用于接管线程池的作业和异步作业的处理。
基准测试表明,在吞吐量方面,使用消息队列优于线程池支持的异步执行器。但是,它确实附带了一个额外的体系结构组件,这当然使设置、维护和监视更加复杂。对于许多用户来说,线程池支持的异步执行器的性能已经足够了。不过,如果所需的性能有所提高,很高兴知道,还有另外一种选择。
Currently, the only option that is supported out-of-the-box is JMS with Spring. The reason for supporting Spring before anything else is because Spring has some very nice features that ease a lot of the pain when it comes to threading and dealing with multiple message consumers. However, the integration is so simple, that it can easily be ported to any message queue implementation or protocol (Stomp, AMPQ, and so on). Feedback is appreciated for what should be the next implementation.
目前,支持开箱即用的唯一选项是JMS with Spring。支持Spring的原因是因为Spring有一些非常好的特性,可以减轻线程和处理多个消息使用者的痛苦。不过,集成非常简单,可以轻松地将其移植到任何消息队列实现或协议(Stomp、AMPQ等)。对于下一步的实现,我们非常感谢您的反馈。
When a new async job is created by the engine, a message is put on a message queue (in a transaction committed transaction listener, so we’re sure the job entry is in the database) containing the job identifier. A message consumer then takes this job identifier to fetch the job, and execute the job. The async executor will not create a thread pool anymore. It will insert and query for timers from a separate thread. When a timer fires, it is moved to the async job table, which now means a message is sent to the message queue too. The ‘reset expired’ thread will also unlock jobs as usual, as message queues can fail too. Instead of ‘unlocking’ a job, a message will now be resent. The async executor will not poll for async jobs anymore.
当引擎创建一个新的异步作业时,会将一条消息放入包含作业标识符的消息队列(在提交事务的事务侦听器中,我们可确定作业条目位于数据库中)。然后,消息使用者使用此作业标识符来获取作业,并执行作业。异步执行器将不再创建线程池。它将从一个单独的线程插入和查询定时器。当定时器触发时,它被移到异步作业表,这意味着消息也被发送到消息队列。“reset expired”线程也将像往常一样解锁作业,因为消息队列也可能失败。现在将重新发送一条消息,而不是“解锁”(‘unlocking’)作业。异步执行器将不再轮询异步作业。
The implementation consists of two classes:
First of all, add the flowable-jms-spring-executor dependency to your project:
实现包括两个类:
• org.flowable.engine.impl.asyncexecutor.JobManager接口的实现,它将消息放入消息队列上,而不是传递给线程池。
• 一个javax.jms.MessageListener实现,该实现使用来自消息队列的消息,使用消息中的作业标识符来获取和执行作业。
首先,将可流flowable-jms-spring-executor依赖项添加到项目中:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-jms-spring-executor</artifactId>
<version>${flowable.version}</version>
</dependency>
To enable the message queue based async executor, in the process engine configuration, the following needs to be done:
要启用基于消息队列的异步执行器,在流程引擎配置中,需要执行以下操作:
Below is a complete example of a Java based configuration, using ActiveMQ as the message queue broker.
Some things to note:
下面是一个完整的基于Java的配置示例,使用ActiveMQ 作为消息队列代理。
注意事项:
@Configuration
public class SpringJmsConfig {
@Bean
public DataSource dataSource() {
// Omitted
}
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
@Bean
public SpringProcessEngineConfiguration processEngineConfiguration(DataSource dataSource, PlatformTransactionManager transactionManager,
JobManager jobManager) {
SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
configuration.setDataSource(dataSource);
configuration.setTransactionManager(transactionManager);
configuration.setDatabaseSchemaUpdate(SpringProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
configuration.setAsyncExecutorMessageQueueMode(true);
configuration.setAsyncExecutorActivate(true);
configuration.setJobManager(jobManager);
return configuration;
}
@Bean
public ProcessEngine processEngine(ProcessEngineConfiguration processEngineConfiguration) {
return processEngineConfiguration.buildProcessEngine();
}
@Bean
public MessageBasedJobManager jobManager(JmsTemplate jmsTemplate) {
MessageBasedJobManager jobManager = new MessageBasedJobManager();
jobManager.setJmsTemplate(jmsTemplate);
return jobManager;
}
@Bean
public ConnectionFactory connectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
activeMQConnectionFactory.setUseAsyncSend(true);
activeMQConnectionFactory.setAlwaysSessionAsync(true);
return new CachingConnectionFactory(activeMQConnectionFactory);
}
@Bean
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setDefaultDestination(new ActiveMQQueue("flowable-jobs"));
jmsTemplate.setConnectionFactory(connectionFactory);
return jmsTemplate;
}
@Bean
public MessageListenerContainer messageListenerContainer(JobMessageListener jobMessageListener) {
DefaultMessageListenerContainer messageListenerContainer = new DefaultMessageListenerContainer();
messageListenerContainer.setConnectionFactory(connectionFactory());
messageListenerContainer.setDestinationName("flowable-jobs");
messageListenerContainer.setMessageListener(jobMessageListener);
messageListenerContainer.setConcurrentConsumers(2);
messageListenerContainer.start();
return messageListenerContainer;
}
@Bean
public JobMessageListener jobMessageListener(ProcessEngineConfiguration processEngineConfiguration) {
JobMessageListener jobMessageListener = new JobMessageListener();
jobMessageListener.setProcessEngineConfiguration(processEngineConfiguration);
return jobMessageListener;
}
}
In the code above, the JobMessageListener and MessageBasedJobManager are the only classes from the flowable-jms-spring-executor module. All the other code is from Spring. As such, when wanting to port this to other queues/protocols, these classes must be ported.
在上面的代码中,JobMessageListener 和MessageBasedJobManager 是唯一的来自flowable-jms-spring-executor 模块的类。所有其他代码都来自Spring。因此,当希望将其移植到其他队列/协议时,必须移植这些类。