Hello,
I have a Service- A which makes an api (feign client) call to Service-B (Flowable service) with its own DB, to start a process instance by a given definition key and return the instance id to Service-A to save it use it for later processing (within Service-A DB). However, I have noticed that when calls are made by diff users (Concurrently) at the same time to create the process instance, the api call made from Service-A to Service-B never returns and the api call times out.
When i took the thread dump, I noticed that one of the thread had locked the db record and hence subsequent call made will not be processed.
Below is the dump details.
"http-nio-80-exec-617" Id=98363 cpu=52761177754 ns usr=51000000000 ns blocked 57 for -1 ms waited 1660 for -1 ms
java.lang.Thread.State: RUNNABLE
locks java.util.concurrent.ThreadPoolExecutor$Worker@20123d7a
at java.base@11.0.6/java.net.SocketInputStream.socketRead0(Native Method)
at java.base@11.0.6/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
at java.base@11.0.6/java.net.SocketInputStream.read(SocketInputStream.java:168)
at java.base@11.0.6/java.net.SocketInputStream.read(SocketInputStream.java:140)
at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:140)
at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:109)
at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:67)
at org.postgresql.core.PGStream.receiveChar(PGStream.java:335)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2000)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:310)
- locked (a org.postgresql.core.v3.QueryExecutorImpl@780a08ae) index 9 frame org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:310)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:149)
at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:138)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185)
at org.flowable.common.engine.impl.db.DbSqlSession.flushRegularInsert(DbSqlSession.java:442)
at org.flowable.common.engine.impl.db.DbSqlSession.flushInsertEntities(DbSqlSession.java:426)
at org.flowable.common.engine.impl.db.DbSqlSession.flushInserts(DbSqlSession.java:406)
at org.flowable.common.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:291)
at org.flowable.common.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:191)
at org.flowable.common.engine.impl.interceptor.CommandContext.close(CommandContext.java:61)
at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:80)
at org.flowable.common.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:49)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at org.flowable.common.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:46)
at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:51)
at org.flowable.engine.impl.RuntimeServiceImpl.startProcessInstanceByKey(RuntimeServiceImpl.java:117)
Below is the api code.
@RequestMapping( value = "/rest/process-instances/{processDefinitionKey}", method = RequestMethod.POST )
public ProcessInstanceRepresentation startNewProcessInstanceByprocessDefinitionKey( @PathVariable String processDefinitionKey,
@RequestBody ProcessInstanceVariable instanceVariables ) throws Exception
{
Map<String, Object> variables = instanceVariables.getPayload();
log.info( "Starting process instance with definition id: {} with variables {} : ",
processDefinitionKey,
variables.toString() );
try
{
ProcessInstance lProcessInstance = runtimeService.startProcessInstanceByKey( processDefinitionKey, variables );
log.info( "Workflow process instance started successfully for def id: {} with instance id {}",
processDefinitionKey,
lProcessInstance.getId() );
ProcessInstanceRepresentation lProcessInstanceRepresentation = new ProcessInstanceRepresentation();
lProcessInstanceRepresentation.setProcessDefinitionKey( processDefinitionKey );
lProcessInstanceRepresentation.setProcessDefinitionName( lProcessInstance.getName() );
lProcessInstanceRepresentation.setId( lProcessInstance.getId() );
lProcessInstanceRepresentation.setProcessDefinitionDeploymentId( lProcessInstance.getDeploymentId() );
lProcessInstanceRepresentation.setProcessDefinitionVersion( lProcessInstance.getProcessDefinitionVersion() );
return lProcessInstanceRepresentation;
}
catch( Exception e )
{
e.printStackTrace();
log.error( "Exception during starting process instance for key", processDefinitionKey );
throw new Exception( "Exception during starting process instance for key" + processDefinitionKey );
}
}
Should i make this call sequential so it just creates instances sequentially (may be make the endpoint synchronized) and return the instances id back to service A ?
Or
Can anyone suggest any better alternative for this ?
Thanks
Venkatesh