I have a requirement, where I have to read a flat text file which is continuously changing. Let's assume I have a file with 100 lines which I read using FlatFileReader in a batch and process those lines. Again when that step gets called let's say after 30 sec, then there are 110 lines. In that case that batch should read from line 101.
I know there is 'linesToSkip' parameter in Reader but I can define it at the start of a batch only not dynamically. Also the file I defined in batch configuration should be reloaded again on call of that Step(Step would be continuous process).
Any idea about this?
Thanks
Niraj
I would suggest the following approach:
Wrap your reader step with a listener and use before and after hooks.
Make sure that both step and FlatFileItemReader bean are defined at the step scope.
In the before step read the last line processed count from some persistence (file/db/etc) and place it on the stepExecutionContext.
Use the value placed on the stepExecutionContext to set the linesToSkip in the FlatFileItemReader using spel
In the after step take the current WriteCount and SkipCount from the execution context sum it with the value from the before step. Persist this value for then next execution
Your listener will look similar to the one below
#Component
public class LineCursorListener implements StepListener {
#BeforeStep
public ExitStatus beforeStep(StepExecution stepExecution){
int curser = 0;//read from persistence
stepExecution.getExecutionContext().put("linesToSkip", curser);
return stepExecution.getExitStatus();
}
#AfterStep
public ExitStatus afterStep(StepExecution stepExecution){
int nextCurser= stepExecution.getWriteCount() + stepExecution.getSkipCount();
nextCurser =nextCurser + stepExecution.getExecutionContext().getInt("linesToSkip");
// persistence the nextCurser
return stepExecution.getExitStatus();
}
}
Your Job xml will be similar to
<batch:job>
...
<batch:step id="processCsv">
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk reader="someFileReader"
writer="writter" commit-interval="10" />
</batch:tasklet>
<batch:listeners>
<batch:listener ref="lineCurserListener" />
</batch:listeners>
</batch:job>
<bean id="someFileReader" scope="step"
class="org.springframework.batch.item.file.FlatFileItemReader" >
...
<property name="linesToSkip" value="#{stepExecutionContext['linesToSkip']}" />
<property name="lineMapper">
...
</property>
</bean>
I am only presenting the spring batch point of view for this issue, I guess that you need to watch out for concurrency issue related to file read/write
Related
I am using Hibernate search to index Data from Postgresql datenbank, while the process takes really long i want to display Process bar to estimate how long it will take to finish indexing, i also want to display which Entity is being indexed.
First i enabled jmx_enabled and generate_statistics in my Persistence.xml
<property name="hibernate.search.generate_statistics" value="true"/>
<property name="hibernate.search.jmx_enabled" value="true"/>
then added the processMotitor to FullTextSession in my Index Class like this
MassIndexerProgressMonitor monitor = new SimpleIndexingProgressMonitor();
FullTextSession fullTextSession = Search.getFullTextSession(em.unwrap(Session.class));
fullTextSession.getStatistics();
fullTextSession.createIndexer(TCase.class).progressMonitor(monitor).startAndWait();
the Problem is that i still don't know how to print the Process results on console while Indexing
According to documentation of SimpleIndexingProgressMonitor you need to have INFO level enabled at package level org.hibernate.search.batchindexing.impl or class level org.hibernate.search.batchindexing.impl.SimpleIndexingProgressMonitor
Can you check your log level?
I am using Atomikos for JTA transaction.
I have following setting for JTA:
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(900);
but when my code perform JTA transaction, then if it takes more than 5 minutes (which is default value) then it throws exception:
Caused by: com.atomikos.icatch.RollbackException: Prepare: NO vote
at com.atomikos.icatch.imp.ActiveStateHandler.prepare(ActiveStateHandler.java:231)
at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:681)
at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:970)
at com.atomikos.icatch.imp.CompositeTerminatorImp.commit(CompositeTerminatorImp.java:82)
at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:336)
at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:190)
... 25 common frames omitted
it looks like its taking the default jta transaction timeout (even though i am setting timeout explicitely (to 15 minutes/900 seconds).
I tried using following properties in application.properties file however it still takes the default timeout value(300 seconds).
spring.jta.atomikos.properties.max-timeout=600000
spring.jta.atomikos.properties.default-jta-timeout=10000
I have also tried with below property but no luck:
spring.transaction.default-timeout=900
Can anyone suggest if I need any other setting? I am using wildfly plugin, spring boot and atomikos api for JTA transaction.
From the Atomikos documentation:
com.atomikos.icatch.max_timeout
Specifies the maximum timeout (in milliseconds) that can be allowed for transactions. Defaults to 300000. This means that calls to UserTransaction.setTransactionTimeout() with a value higher than configured here will be max'ed to this value. For 4.x or higher, a value of 0 means no maximum (i.e., unlimited timeouts are allowed).
Indeed, if you take a look at the Atomikos library source code (for both versions 4.0.0M4 and 3.7.0), in the createCC method from class com.atomikos.icatch.imp.TransactionServiceImp you will see:
387: if ( timeout > maxTimeout_ ) {
388: timeout = maxTimeout_;
389: //FIXED 20188
390: LOGGER.logWarning ( "Attempt to create a transaction with a timeout that exceeds maximum - truncating to: " + maxTimeout_ );
391: }
So any attempt to specify a longer transaction timeout gets capped to maxTimeout_ which has a default value of 300000 set during initialization if none is specified.
You can set the com.atomikos.icatch.max_timeout as a JVM argument with:
-Dcom.atomikos.icatch.max_timeout=900000
or you could use The Advanced Case recipe specified in the Configuration for Spring Section from the Atomikos documentation.
I've resolved similar problem where configuration in application.yml (or application. properties) of Spring Boot did not get picked up.
There was even a log that I later found mentioned in official docs.
However, I added transactions.properties file (next to the application.yml) where I set mine desired properties.
# Atomikos properties
# Service must be defined!
com.atomikos.icatch.service = com.atomikos.icatch.standalone.UserTransactionServiceFactory
# Override default properties.
com.atomikos.icatch.log_base_dir = ./atomikos
Some properties can be set within transactions.properties and other within jta.properties file.
I am as a client inserting/updating/fetching values to/from back-end DB via JCA files creating business service and making the call. I am facing problem while performing insert/update call as for all the request i will be getting success response irrespective of the DB getting added/updated. If there is a way to confirm like these many rows got updated after insert/update DB then it confirms like operation is successful.
Below is the simple JCA file to update the DB, can you please let me know what extra configuration i need to do to get the number of rows get updated..!
<adapter-config name="RetrieveSecCustRelationship" adapter="Database Adapter" wsdlLocation="RetrieveSecCustRelationship.wsdl" xmlns="http://platform.integration.oracle/blocks/adapter/fw/metadata">
<connection-factory location="eis/DB/Database" UIConnectionName="Database" adapterRef=""/>
<endpoint-interaction portType="RetrieveSecCustRelationship_ptt" operation="RetrieveSecCustRelationship">
<interaction-spec className="oracle.tip.adapter.db.DBPureSQLInteractionSpec">
<property name="SqlString" value=**"update CUSTOMER_INSTALLED_PRODUCT set CUSTOMER_ID=? where CUSTOMER_ID=?"**/>
<property name="GetActiveUnitOfWork" value="false"/>
<property name="QueryTimeout" value="6"/>
</interaction-spec>
<input/>
<output/>
</endpoint-interaction>
</adapter-config>
Thanks & Regards
I'm afraid you will need to wrap it in PL/SQL and then extend that PL/SQL so number of affected rows is being returned. Then you could extract this value from response variable with XPath.
ENV: camunda 7.4, BPMN 2.0
Given a process, which can be started by multiple start message events.
is it possible to query process instances started by specific messages identified by message name?
if yes, how?
if no, why?
if not at the moment, when?
Some APIs like IncidentMessages?
That is no out-of-the-box feature but should be easy to build by using process variables.
The basic steps are:
1. Implement an execution listener that sets the message name as a variable:
public class MessageStartEventListener implements ExecutionListener {
public void notify(DelegateExecution execution) throws Exception {
execution.setVariable("startMessage", "MessageName");
}
}
Note that via DelegateExecution#getBpmnModelElementInstance you can access the BPMN element that the listener is attached to, so you could determine the message name dynamically.
2. Declare the execution listener at the message start events:
<process id="executionListenersProcess">
<startEvent id="theStart">
<extensionElements>
<camunda:executionListener
event="start" class="org.camunda.bpm.examples.bpmn.executionlistener.MessageStartEventListener" />
</extensionElements>
<messageEventDefinition ... />
</startEvent>
...
</process>
Note that with a BPMN parse listener, you can add such a listener programmatically to every message start event in every process definition. See this example.
3. Make a process instance query filtering by that variable
RuntimeService runtimeService = processEngine.getRuntimeService();
List<ProcessInstance> matchingInstances = runtimeService
.createProcessInstanceQuery()
.variableValueEquals("startMessage", "MessageName")
.list();
We have a spring-integration application where we would like to deal with the messages on the error channel.At a minimum we would like to extract the history and log it so we can visualise where exactly it failed etc
Here is a brief markup of just this bit
<int:poller id="defaultPoller" default="true" fixed-delay="5000" />
<int:channel id="MyCustomErrorChannel">
<int:queue capacity="10"/>
</int:channel>
<int:header-enricher id="errorMsg.HeaderEnricher"
input-channel="errorChannel"
output-channel="MyCustomErrorChannel">
<int:header name="history" expression="payload.failedMessage.headers" />
</int:header-enricher>
<int:service-activator input-channel="MyCustomErrorChannel" ref="errorLogger" method="logError"/>
<bean id="errorLogger" class="com.dataprep.util.ErrorLogger" />
The idea is to define our custom error channel MyCustomErrorChannel. Any error that ends up in the default errorChannel gets its header's enriched before being put out on MyCustomErrorChannel
Lastly we have a logger that reads the messages from MyCustomErrorChannel and logs the payload which is the underlying exception and also the history.
I notice that the history in my logger is always 3 steps
errorChannel,errorMsg.HeaderEnricher,pbSwiftRouterErrorChannel i.e nothing prior to this message landing on the errorChannel is obtainable in the history.
How do I get hold of the original message's history (i.e the history of the faulty message which somehow landed on the default error channel as a new Error Message)
Could you please take a look at my header enricher and let me know how to access the headers on the failed message and stuff it to the error message?
Is it doable at all ?
To replace existing headers you should use overwrite="true", because the history is built for the ErrorChannel, too.
You should override exactly with history header, not the whole headers. Therefore your expression must be like this:
<int:header name="history"
expression="payload.failedMessage.headers.history"
overwrite="true"/>