<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: multiple engines on single database - tenant question in Alfresco Archive</title>
    <link>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207367#M160497</link>
    <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;SPAN&gt;It doesn't look that i need providing my own JobExecutor to make different Activiti engine apps to poll their own jobs by tenantId. &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;There were some threads already started regarding &amp;lt;i&amp;gt;"multiple engines - single database"&amp;lt;/i&amp;gt; (&lt;/SPAN&gt;&lt;A href="https://forums.activiti.org/content/could-multiple-activiti-engines-share-one-repository" rel="nofollow noopener noreferrer"&gt;Could multiple Activiti engines share one Repository?&lt;/A&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;A href="https://forums.activiti.org/content/usage-more-one-activiti-engines-one-database" rel="nofollow noopener noreferrer"&gt;Usage of more than one Activiti Engines on one database &lt;/A&gt;&lt;SPAN&gt;) but i didn't find particular answer to my question.&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;I'll describe how i made &amp;lt;b&amp;gt;polling jobs by tenantId&amp;lt;/b&amp;gt; per multiple Activiti engines running on single DB:&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;1. Provide custom engine configuration&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;public class CustomSpringProcessEngineConfiguration extends SpringProcessEngineConfiguration {&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static final String CUSTOM_MYBATIS_MAPPING_FILE = "com/custom/activiti/query/custom-mappings.xml";&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected InputStream getMyBatisXmlConfigurationSteam() {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ReflectUtil.getResourceAsStream(CUSTOM_MYBATIS_MAPPING_FILE);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;The &amp;lt;i&amp;gt;custom-mappings.xml&amp;lt;/i&amp;gt; actually is a copy of Activiti &amp;lt;i&amp;gt;mappings.xml&amp;lt;/i&amp;gt; with my customizations and overriding the Activiti &amp;lt;i&amp;gt;Job.xml&amp;lt;/i&amp;gt; implementation.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;2. Create my custom job entity manager &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;import org.activiti.engine.impl.interceptor.Session;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;import org.activiti.engine.impl.interceptor.SessionFactory;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;import org.activiti.engine.impl.persistence.entity.JobEntityManager;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;public class CustomJobEntityManagerFactory implements SessionFactory {&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; public Class&amp;lt;?&amp;gt; getSessionType() {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; return JobEntityManager.class;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; public Session openSession() {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; return new CustomJobEntityManager();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;provide the implementation for the custom job entity manager:&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;public class CustomJobEntityManager extends JobEntityManager {&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; public List&amp;lt;JobEntity&amp;gt; findNextJobsToExecute(Page page) {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProcessEngineConfiguration processEngineConfig = Context.getProcessEngineConfiguration();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Map&amp;lt;String, Object&amp;gt; parameter = Maps.newHashMap();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Date now = processEngineConfig.getClock().getCurrentTime();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; parameter.put("tenantId",&amp;nbsp; retrieveCustomTenantId());&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; parameter.put("dueDate", now);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return getDbSqlSession().selectList("selectNextJobsToExecute", parameter, page);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; // TODO override other queries by duedate …&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;3. Add custom job entity manager to custom session list in Spring process engine configuration based on my CustomSpringProcessEngineConfiguration with overriden &amp;lt;i&amp;gt;getMyBatisXmlConfigurationSteam&amp;lt;/i&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;bean id="customPocessEngineConfiguration" class="com.custom.activiti.engine.CustomSpringProcessEngineConfiguration"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="dataSource" ref="dataSource" /&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="transactionManager" ref="transactionManager" /&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="customSessionFactories"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;list&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ref bean="activitiCustomJobEntiyManagerFactory"/&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/list&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/property&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;bean id="activitiCustomJobEntiyManagerFactory" class="com.custom.activiti.job.CustomJobEntityManagerFactory"/&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;4. create a mirror of Activiti Job.xml -&amp;gt; CustomJob.xml with same queries appended with tenantId in &amp;lt;i&amp;gt;WHERE&amp;lt;/i&amp;gt; clause and include it in my &amp;lt;i&amp;gt;com/custom/activiti/query/custom-mappings.xml&amp;lt;/i&amp;gt; specified in my overriden process engine configuration &amp;lt;i&amp;gt;CustomSpringProcessEngineConfiguration &amp;lt;/i&amp;gt;:&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;?xml version="1.0" encoding="UTF-8" ?&amp;gt; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;!DOCTYPE mapper PUBLIC "-//&lt;/SPAN&gt;&lt;A href="http://mybatis.org//DTD" rel="nofollow noopener noreferrer"&gt;mybatis.org//DTD&lt;/A&gt;&lt;SPAN&gt; Mapper 3.0//EN" "&lt;/SPAN&gt;&lt;A href="http://mybatis.org/dtd/mybatis-3-mapper.dtd" rel="nofollow noopener noreferrer"&gt;http://mybatis.org/dtd/mybatis-3-mapper.dtd&lt;/A&gt;&lt;SPAN&gt;"&amp;gt; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;mapper namespace="org.activiti.engine.impl.persistence.entity.JobEntity"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;select id="selectNextJobsToExecute" parameterType="org.activiti.engine.impl.db.ListQueryParameterObject" resultMap="jobResultMap"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; ${limitBefore}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; select &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RES.* ${limitBetween}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; from ${prefix}ACT_RU_JOB RES&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LEFT OUTER JOIN ${prefix}ACT_RU_EXECUTION PI ON PI.ID_ = RES.PROCESS_INSTANCE_ID_&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; where (RES.RETRIES_ &amp;amp;gt; 0)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and (RES.DUEDATE_ is null or RES.DUEDATE_ &amp;amp;lt;= #{parameter.dueDate, jdbcType=TIMESTAMP})&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and (RES.LOCK_OWNER_ is null or RES.LOCK_EXP_TIME_ &amp;amp;lt;= #{parameter.dueDate, jdbcType=TIMESTAMP})&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and (&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (RES.EXECUTION_ID_ is null)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; or &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (PI.SUSPENSION_STATE_ = 1)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include refid="tenantIdCriteria"/&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ${limitAfter}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;/select&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; &amp;lt;sql id="tenantIdCriteria"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;if test="parameter.tenantId != null"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; and RES.TENANT_ID_ = #{parameter.tenantId}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;/if&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; &amp;lt;/sql&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;Thats it.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;Couldn't get to a cleaner solution at the moment. What i don't like here - i keep a copy of &amp;lt;i&amp;gt;mappings.xml&amp;lt;/i&amp;gt; and override &amp;lt;i&amp;gt;Job.xml&amp;lt;/i&amp;gt;. Such implementation complicates upgrading to new Activiti versions and it may introduce new bugs.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;b&amp;gt;Questions:&amp;lt;/b&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;UL&gt;&lt;LI&gt;The ACT_RU_JOB contains TENANT_ID_ and it&amp;nbsp; is filled when job created. Why tenantId is not used in job polling? Maybe there are some threats for which polling by tenantId was not introduced?&lt;/LI&gt;&lt;LI&gt;&amp;lt;i&amp;gt;org.activiti.engine.impl.persistence.entity.JobEntityManager&amp;lt;/i&amp;gt; works with the &amp;lt;b&amp;gt;default job executor&amp;lt;/b&amp;gt;. If i want the &amp;lt;b&amp;gt;new async job executor&amp;lt;/b&amp;gt; to use tenantId - would it be enough to override &amp;lt;i&amp;gt;org.activiti.engine.impl.persistence.entity.data.impl.MybatisJobDataManager&amp;lt;/i&amp;gt; the same way as the &amp;lt;i&amp;gt;JobEntityManager&amp;lt;/i&amp;gt;?&lt;/LI&gt;&lt;LI&gt;Is there any other solution to make polling jobs by tenantId without copying &amp;lt;i&amp;gt;Job.xml&amp;lt;/i&amp;gt; as described above?&lt;/LI&gt;&lt;LI&gt;Would JobEntityManager/MybatisJobDataManager cover all job executions polling that occur in BPMN asynchronously (timers, parallel gateway, async…)?&lt;/LI&gt;&lt;/UL&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
    <pubDate>Fri, 06 Nov 2015 14:38:15 GMT</pubDate>
    <dc:creator>btomas</dc:creator>
    <dc:date>2015-11-06T14:38:15Z</dc:date>
    <item>
      <title>multiple engines on single database - tenant question</title>
      <link>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207365#M160495</link>
      <description>Activiti engine A and engine B&amp;nbsp; (v.5.17)&amp;nbsp; are running on single database. To distinguish data content per engine tenancy is used - A has tenantId=tenant_A and B has tenantId=tenant_B. The situation similar to&amp;nbsp; Shared Database Multi-tenancy  but here i've got separate applications running Activiti en</description>
      <pubDate>Wed, 04 Nov 2015 16:39:04 GMT</pubDate>
      <guid>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207365#M160495</guid>
      <dc:creator>btomas</dc:creator>
      <dc:date>2015-11-04T16:39:04Z</dc:date>
    </item>
    <item>
      <title>Re: multiple engines on single database - tenant question</title>
      <link>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207366#M160496</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;SPAN&gt;Hi,&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;BLOCKQUOTE class="jive-quote"&gt;* how tenancy could be applied when acquiring for async jobs?&lt;/BLOCKQUOTE&gt;&lt;SPAN&gt;Multitenancy was not meant to distinguish between nodes (A,B). You can implement your own job executor.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;The second question -&amp;gt; I do not have any good proposal.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;Regards&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;Martin&lt;/SPAN&gt;&lt;BR /&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Thu, 05 Nov 2015 10:31:13 GMT</pubDate>
      <guid>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207366#M160496</guid>
      <dc:creator>martin_grofcik</dc:creator>
      <dc:date>2015-11-05T10:31:13Z</dc:date>
    </item>
    <item>
      <title>Re: multiple engines on single database - tenant question</title>
      <link>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207367#M160497</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;SPAN&gt;It doesn't look that i need providing my own JobExecutor to make different Activiti engine apps to poll their own jobs by tenantId. &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;There were some threads already started regarding &amp;lt;i&amp;gt;"multiple engines - single database"&amp;lt;/i&amp;gt; (&lt;/SPAN&gt;&lt;A href="https://forums.activiti.org/content/could-multiple-activiti-engines-share-one-repository" rel="nofollow noopener noreferrer"&gt;Could multiple Activiti engines share one Repository?&lt;/A&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;A href="https://forums.activiti.org/content/usage-more-one-activiti-engines-one-database" rel="nofollow noopener noreferrer"&gt;Usage of more than one Activiti Engines on one database &lt;/A&gt;&lt;SPAN&gt;) but i didn't find particular answer to my question.&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;I'll describe how i made &amp;lt;b&amp;gt;polling jobs by tenantId&amp;lt;/b&amp;gt; per multiple Activiti engines running on single DB:&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;1. Provide custom engine configuration&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;public class CustomSpringProcessEngineConfiguration extends SpringProcessEngineConfiguration {&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static final String CUSTOM_MYBATIS_MAPPING_FILE = "com/custom/activiti/query/custom-mappings.xml";&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected InputStream getMyBatisXmlConfigurationSteam() {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ReflectUtil.getResourceAsStream(CUSTOM_MYBATIS_MAPPING_FILE);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;The &amp;lt;i&amp;gt;custom-mappings.xml&amp;lt;/i&amp;gt; actually is a copy of Activiti &amp;lt;i&amp;gt;mappings.xml&amp;lt;/i&amp;gt; with my customizations and overriding the Activiti &amp;lt;i&amp;gt;Job.xml&amp;lt;/i&amp;gt; implementation.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;2. Create my custom job entity manager &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;import org.activiti.engine.impl.interceptor.Session;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;import org.activiti.engine.impl.interceptor.SessionFactory;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;import org.activiti.engine.impl.persistence.entity.JobEntityManager;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;public class CustomJobEntityManagerFactory implements SessionFactory {&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; public Class&amp;lt;?&amp;gt; getSessionType() {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; return JobEntityManager.class;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; public Session openSession() {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; return new CustomJobEntityManager();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;provide the implementation for the custom job entity manager:&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;public class CustomJobEntityManager extends JobEntityManager {&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; @Override&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; public List&amp;lt;JobEntity&amp;gt; findNextJobsToExecute(Page page) {&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProcessEngineConfiguration processEngineConfig = Context.getProcessEngineConfiguration();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Map&amp;lt;String, Object&amp;gt; parameter = Maps.newHashMap();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Date now = processEngineConfig.getClock().getCurrentTime();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; parameter.put("tenantId",&amp;nbsp; retrieveCustomTenantId());&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; parameter.put("dueDate", now);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return getDbSqlSession().selectList("selectNextJobsToExecute", parameter, page);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; }&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt; // TODO override other queries by duedate …&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;3. Add custom job entity manager to custom session list in Spring process engine configuration based on my CustomSpringProcessEngineConfiguration with overriden &amp;lt;i&amp;gt;getMyBatisXmlConfigurationSteam&amp;lt;/i&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;bean id="customPocessEngineConfiguration" class="com.custom.activiti.engine.CustomSpringProcessEngineConfiguration"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="dataSource" ref="dataSource" /&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="transactionManager" ref="transactionManager" /&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="customSessionFactories"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;list&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ref bean="activitiCustomJobEntiyManagerFactory"/&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/list&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/property&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;bean id="activitiCustomJobEntiyManagerFactory" class="com.custom.activiti.job.CustomJobEntityManagerFactory"/&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;4. create a mirror of Activiti Job.xml -&amp;gt; CustomJob.xml with same queries appended with tenantId in &amp;lt;i&amp;gt;WHERE&amp;lt;/i&amp;gt; clause and include it in my &amp;lt;i&amp;gt;com/custom/activiti/query/custom-mappings.xml&amp;lt;/i&amp;gt; specified in my overriden process engine configuration &amp;lt;i&amp;gt;CustomSpringProcessEngineConfiguration &amp;lt;/i&amp;gt;:&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;?xml version="1.0" encoding="UTF-8" ?&amp;gt; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;!DOCTYPE mapper PUBLIC "-//&lt;/SPAN&gt;&lt;A href="http://mybatis.org//DTD" rel="nofollow noopener noreferrer"&gt;mybatis.org//DTD&lt;/A&gt;&lt;SPAN&gt; Mapper 3.0//EN" "&lt;/SPAN&gt;&lt;A href="http://mybatis.org/dtd/mybatis-3-mapper.dtd" rel="nofollow noopener noreferrer"&gt;http://mybatis.org/dtd/mybatis-3-mapper.dtd&lt;/A&gt;&lt;SPAN&gt;"&amp;gt; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;mapper namespace="org.activiti.engine.impl.persistence.entity.JobEntity"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;select id="selectNextJobsToExecute" parameterType="org.activiti.engine.impl.db.ListQueryParameterObject" resultMap="jobResultMap"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; ${limitBefore}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; select &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RES.* ${limitBetween}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; from ${prefix}ACT_RU_JOB RES&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LEFT OUTER JOIN ${prefix}ACT_RU_EXECUTION PI ON PI.ID_ = RES.PROCESS_INSTANCE_ID_&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; where (RES.RETRIES_ &amp;amp;gt; 0)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and (RES.DUEDATE_ is null or RES.DUEDATE_ &amp;amp;lt;= #{parameter.dueDate, jdbcType=TIMESTAMP})&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and (RES.LOCK_OWNER_ is null or RES.LOCK_EXP_TIME_ &amp;amp;lt;= #{parameter.dueDate, jdbcType=TIMESTAMP})&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and (&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (RES.EXECUTION_ID_ is null)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; or &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (PI.SUSPENSION_STATE_ = 1)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include refid="tenantIdCriteria"/&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ${limitAfter}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;/select&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; &amp;lt;sql id="tenantIdCriteria"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;if test="parameter.tenantId != null"&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; and RES.TENANT_ID_ = #{parameter.tenantId}&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;nbsp; &amp;lt;/if&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt; &amp;lt;/sql&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN&gt;….&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;/code&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;Thats it.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;Couldn't get to a cleaner solution at the moment. What i don't like here - i keep a copy of &amp;lt;i&amp;gt;mappings.xml&amp;lt;/i&amp;gt; and override &amp;lt;i&amp;gt;Job.xml&amp;lt;/i&amp;gt;. Such implementation complicates upgrading to new Activiti versions and it may introduce new bugs.&lt;/SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;SPAN&gt;&amp;lt;b&amp;gt;Questions:&amp;lt;/b&amp;gt;&lt;/SPAN&gt;&lt;BR /&gt;&lt;UL&gt;&lt;LI&gt;The ACT_RU_JOB contains TENANT_ID_ and it&amp;nbsp; is filled when job created. Why tenantId is not used in job polling? Maybe there are some threats for which polling by tenantId was not introduced?&lt;/LI&gt;&lt;LI&gt;&amp;lt;i&amp;gt;org.activiti.engine.impl.persistence.entity.JobEntityManager&amp;lt;/i&amp;gt; works with the &amp;lt;b&amp;gt;default job executor&amp;lt;/b&amp;gt;. If i want the &amp;lt;b&amp;gt;new async job executor&amp;lt;/b&amp;gt; to use tenantId - would it be enough to override &amp;lt;i&amp;gt;org.activiti.engine.impl.persistence.entity.data.impl.MybatisJobDataManager&amp;lt;/i&amp;gt; the same way as the &amp;lt;i&amp;gt;JobEntityManager&amp;lt;/i&amp;gt;?&lt;/LI&gt;&lt;LI&gt;Is there any other solution to make polling jobs by tenantId without copying &amp;lt;i&amp;gt;Job.xml&amp;lt;/i&amp;gt; as described above?&lt;/LI&gt;&lt;LI&gt;Would JobEntityManager/MybatisJobDataManager cover all job executions polling that occur in BPMN asynchronously (timers, parallel gateway, async…)?&lt;/LI&gt;&lt;/UL&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Fri, 06 Nov 2015 14:38:15 GMT</pubDate>
      <guid>https://connect.hyland.com/t5/alfresco-archive/multiple-engines-on-single-database-tenant-question/m-p/207367#M160497</guid>
      <dc:creator>btomas</dc:creator>
      <dc:date>2015-11-06T14:38:15Z</dc:date>
    </item>
  </channel>
</rss>

