I am trying to implement parallel processing using spring boot and spring batch. This batch will be triggered from UI with some required parameters
I need to create steps based on the request parameters, I tried as below,
The rest controller looks,
JobParameters jobParameters = new JobParametersBuilder().addLong("JobID",System.currentTimeMillis())
.addString("fileName", filename)
.addString("buisinessDate", model.getGeneralServiceModel().getBusinessDate())
.addString("source", model.getGeneralServiceModel().getSource())
.toJobParameters();
jobLauncher.run(job, jobParameters);
And the batch config:
Flow masterFlow = (Flow)new FlowBuilder("masterFlow").start(stepOne()).build();
List<Step> steps = new ArrayList<Step>();
for (ConcurrentLinkedQueue date : taskOne.readFile()) {
steps.add(createStep(date));
}
return jobs.get("myJob")
.start(masterFlow)
.next(createParallelFlow(steps))
.end()
.build();
The masterFlow reads the job parameters into its variables, and the readFile() gives the list (based on this the steps has to be created), for this the jobParameters are required.
The problem is:
While starting my application itself the readFile() is getting executed. but I need to get it executed when job triggers through RestController since it has the required parameters.
How can I stop this execution while starting the application?
I need steps to be created based on step1 result
Creating steps is something that you do at configuration time. Step1 result can only be known at runtime. So in order to do this, you would need to access the application context at runtime and register step beans dynamically based on the result of Step1. I am not sure if this is really what you aim to do.
However, if you want to execute (not create, but execute) those steps based on step1's result, then you can use a JobExecutionDecider. Please refer to Programmatic Flow Decisions for more details and code example. A similar question can be found here: How to use decider in Spring batch?
But in order to process step1 I need request parameters.
I see you have managed to get request parameters and set them as job parameters. What you can do is access those job parameters in your step through the step execution. Here is an example if your step is a simple Tasklet:
class MyTasklet implements Tasklet {
#Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Map<String, Object> jobParameters = chunkContext.getStepContext().getJobParameters();
// use job parameters
return RepeatStatus.FINISHED;
}
}
If your step is a chunk-oriented tasklet, you can use a StepListener#beforeStep to get access to the step execution.
Hope this helps.
Related
Is it possible to use some kind of #Before annotation ?
I want to 'pre-load' datas (POST) before to launch my tests (GET).
But I only want parallel executions on the GET.
I was thinking to define a method with #LoadWith("preload_generation.properties") with :
number.of.threads=1
ramp.up.period.in.seconds=1
loop.count=1
Just to be sure that we execute it only once.
But it looks like I cannot choose the order of execution, and I need this POST method to be the first one executed.
I also tried to put a TestMappings with my 'loading method' at the top of the class.
But it doesn't work neither.
I am not aware of any way that ZeroCode would be able to do this as it is specific to only re-leveraging tests already written in JUnit. My suggestion would be to follow a bit more traditional approach and use standard JUnit setup methods
#BeforeClass
public static void setupClass() {
// setup before the entire class
}
#Before
public void setup() {
// setup before each individual test
}
rather than attempting to use a tool outside of its intended purposes.
As per your described scenario above that you want to ensure data is loaded before your tests are executed, especially in the case of being run under load by ZeroCode it is suggested that you determine how to create your data using the
#BeforeClass
public static void setupClass() {
// setup before the entire class
}
While this may take a bit more thought into how you create your data by creating it before all the tests it will ensure that your load test is excluding data setup time.
Assuming that I have a Cucumber feature tagged #api
#api
Feature: BankID authentication
Scenario Outline: Successful authentication of user using BankID
Given the initial flow start URLĀ
When I enter that "<url>" into my browser
...
and steps for execution as below:
public class ApiSteps implements En {
public ApiSteps (ABCinjected abcInjected) {
Given("^the initial flow start URLĀ $", () -> {});
When("^I enter that \"([^\"]*)\" into my browser$", abcInjected::navigateToAuthenticationPage);
...
}
Even if I define this feature not to be executed by specifying different Cucumber tags or explicitly specifying tags = {"not #api"} , although steps themselves are not executed per se, Picocontainer still creates and injects instance of ABCinjected class, which is undesirable. Is it possible to control this behavior? I assume if feature is tagged as not to be executed and related scenario/steps are ignored, consecutively DI should not happen.
I got response from Cucumber contributor on Github:
When using lamda steddefs the class has to be instantiated to register
the steps. And we would need to know the steps defined by the class to
determine if we should instantiate it. This is a dead lock of
requirements.
Another recommendation is to set different packages for steps (api, units etc) and set different glue on runtime.
https://github.com/cucumber/cucumber-jvm/issues/1672
We are using cron based triggers in our file and db polling. Sometimes we like to know if this is the last poll or not. Is this something available in spring integration?
I am not sure what you mean by "last" - last today?
It's not too hard to write a custom version of the CronTrigger to call this.sequenceGenerator.next(...) again with the new result to see if the next poll will be tomorrow.
The question is really what action do you want to take if that occurs? Only knowing it inside the trigger doesn't help very much; I guess you could set a boolean lastToday and test it elsewhere in your app.
Spring Integration 4.2 (currently at milestone 2) has conditional pollers which would allow you to take some action after the last poll (as determined above) completes.
You can do that only from the custom Trigger implementation. For example we often show OnlyOnceTrigger:
#Bean
public Trigger onlyOnceTrigger() {
return new Trigger() {
private final AtomicBoolean invoked = new AtomicBoolean();
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
return this.invoked.getAndSet(true) ? null : new Date();
}
};
}
You can inject to your version the ApplicationEventPublisher and in case of the end for triggering (the next date as null) you emit some custom ApplicationEvent.
From other side you configure an <int-event:inbound-channel-adapter> for that event. And your Spring Integration application is ready to react for that!
Seems for me it's just enough to extend CronTrigger and invoke super.nextExecutionTime() for your case...
I want to make a custom camel processor to behave as a custom component.I read it as it as possible from http://camel.apache.org/processor.html - section--> Turning your processor into a full component.
Here the Custom Processor created will have to do the job when i call
someComponent://action1?param1=value1¶m2=value2
in the route.
For this i created a sample component using maven catalog.This created Endpoint,Consumer, Producer and Component classes.
The link says that the component should return ProcessorEndpoint which i have done.
So, Endpoint looks as below
public class SampleEndpoint extends ProcessorEndpoint{
// Automatically Generated code begins
public Producer createProducer() throws Exception{
return new SampleProducer(this, processor);
}
public Consumer createConsumer() throws Exception{
throw new UnsupportedOperationException("This operation is not permitted....");
}
// Automatically generated code ends here
//added below to make custom processor work for custom component
public Processor createProcessor(Processor processor){
return new SampleProcessor();
}
}
But, here the code in the processor is not getting executed instead the code in the SampleProducer gets executed.
Here i want the processor to be excuted.How do i do that?
When extending ProcessorEndpoint, the Producer from createProducer() will handle the exchange, i.e. Producer.process(Exchange exchange).
This is why you are seeing SampleProducer being used. But if you wanted to delegate to a processor, you could probably just change your code to be:
return new SampleProducer(this, new SampleProcessor());
My best advice would be to attach a debugger and put breakpoints in your SampleEndpoint, SampleProducer and SampleProcessor methods to see what gets called and when.
Is there any way to continue executing Cucumber Steps even when one of the steps fails. In my current setup when a step fails , cucumber skips remaining steps....I wonder if there is some way to twick cucumber runner setup..
I could comment out failing steps but its not practical when you dont know which step will fail...If i could continue with remaining step i would know complete set of failing Tests in one shot....rather than going in cycle over cycle...
Environment: Cucumber JVM , R , Java , Ibatis , Spring Framework, Maven
It is not a good idea to continue executing steps after a step failure because a step failure can leave the World with an invariant violation. A better strategy is to increase the granularity of your scenarios. Instead of writing a single scenario with several "Then" statements, use a list of examples to separately test each postconditions. Sometimes a scenario outline and list of examples can consolidate similar stories. https://docs.cucumber.io/gherkin/reference/#scenario-outline
There is some discussion about adding a feature to tag certain steps to continue after failure. https://github.com/cucumber/cucumber/issues/79
One way would be to catch all the assertion errors and decide in the last step whether to fail or pass the test case. In this case, you can tailor it, say, check at any step to see if there is more than n errors and fail the test, if so.
Here's what I have done:
initialize a StringBuffer for Errors in your #Before for the test cases
catch the Assertion Errors and add to the StringBuffer, so that, they do not get thrown and terminate the test case.
Check the StringBuffer to determine whether to fail the test case.
StringBuffer verificationErrors;
// Initialize your error SringBuffer here
#Before
public void initialize() {
verificationErrors = new StringBuffer();
}
// The following is one of the steps in the test case where I need to assert something
#When("^the value is (\\d+)$")
public void the_result_should_be(int arg1) {
try {
assertEquals(arg1, 0);
}
catch(AssertionError ae) {
verificationErrors.append("Value is incorrect- "+ae.getMessage());
}
Check the StringBuffer in #After or in the last step of test case to determine if you can pass it or fail it, as follows:
if (!(verificationErrors.size()==0)) {
fail(verificationErrors.toString());
}
The only issue would be that, in the report, all the steps would look green but the test case looks failed. Then you might have to look through the Errors String to know which step(s) failed. You could add extra information to the String whenever there is an Assertion Error to help you locate the step easily.
Use SoftAssert to accumulate all assertion failures. Then tag your step definitions class as #ScenarioScoped and in step definitions class add a method tagged #After where you do mySoftAssert.assertAll();
i.e.
import io.cucumber.guice.ScenarioScoped;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Then;
#ScenarioScoped
public class MyStepDefinitions {
SoftAssert mySoftAssert=new SoftAssert();
#Then("check something")
public void checkSomething() {
mySoftAssert.assertTrue(actualValue>expectedMinValue);
}
#After
public void afterScenario(Scenario scenario) throws Exception {
mySoftAssert.assertAll();
}
}