EJB Schedule issue on WebLogic - scheduler

I have an EJB with a method that has an #schedule attribute configured to run at 5 PM every evening. The EJB is deployed on WebLogic server that gets restarted every morning at 4 AM.
Problem: The EJB method sendSummaryEmailForReqs() gets triggered during the server restart at 4 AM even though the method is scheduled to trigger ONLY at 5 PM.
Any pointers on resolving this issue would be highly appreciated.
#Stateless
#LocalBean
#TransactionManagement(TransactionManagementType.CONTAINER)
#TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
public class SendEmail implements Serializable {
private static final Logger LOGGER = Logger.getLogger(SendEmail.class.getName());
private static final long serialVersionUID = -3511061216660424373L;
#EJB(beanName = "requestImpl")
RequestImplRemote requestImpl;
#EJB(beanName = "UtilityImpl")
UtilityImplRemote utilityImpl;
#Context
private ServletContext context;
#Schedule(dayOfWeek = "Mon-Sun", month = "*", hour = "17", dayOfMonth = "*", year = "*", minute = "0", second = "0")
public void sendSummaryEmailForReqs() {
LOGGER.log(Level.INFO, "sendSummaryEmailForReqs:: {0}", new Date());
try {
//... ... ... ...
//... ... ... ...
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
}
}

Related

Reset scheduled job after completion

I have an scheduled job implemented with Spring batch. Right now when it finishes it doesn't start again because it is detected as completed, is it possible to reset its state after completion?
#Component
class JobScheduler {
#Autowired
private Job job1;
#Autowired
private JobLauncher jobLauncher;
#Scheduled(cron = "0 0/15 * * * ?")
public void launchJob1() throws Exception {
this.jobLauncher.run(this.job1, new JobParameters());
}
}
#Configuration
public class Job1Configuration{
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()
.from(this.step1()).on(STEP1_STATUS.READY.get()).to(this.step2())
.next(this.step3())
.end()
.build();
}
}
I know I can set a job parameter with the time or the id, but this will launch a new execution every 15 minutes. I want to repeat the same execution until is completed without errors, and then, execute a new one.
You can't restart your job because you're setting the job status to COMPLETE by calling end() in .start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end().
You should instead either fail the job by calling .start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).fail()
or stop the job by calling .start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).stopAndRestart(step1())
Those options will mean the job status is either FAILED or STOPPED instead of COMPLETE which means that if you launch the job with the same JobParameters, it will restart the previous job execution.
See https://docs.spring.io/spring-batch/docs/current/reference/html/step.html#configuringForStop
To launch the job in a way that handles restarting previous instances or starting a new instance, you could look at how the SimpleJobService in spring-batch-admin does it and modify the launch method slightly for your purposes. This requires you to specify an incremental job parameter that is used to launch new instances of your job.
https://github.com/spring-attic/spring-batch-admin/blob/master/spring-batch-admin-manager/src/main/java/org/springframework/batch/admin/service/SimpleJobService.java#L250
#Override
public JobExecution launch(String jobName, JobParameters jobParameters) throws NoSuchJobException,
JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
JobParametersInvalidException {
JobExecution jobExecution = null;
if (jobLocator.getJobNames().contains(jobName)) {
Job job = jobLocator.getJob(jobName);
JobExecution lastJobExecution = jobRepository.getLastJobExecution(jobName, jobParameters);
boolean restart = false;
if (lastJobExecution != null) {
BatchStatus status = lastJobExecution.getStatus();
if (status.isUnsuccessful() && status != BatchStatus.ABANDONED) {
restart = true;
}
}
if (job.getJobParametersIncrementer() != null && !restart) {
jobParameters = job.getJobParametersIncrementer().getNext(jobParameters);
}
jobExecution = jobLauncher.run(job, jobParameters);
if (jobExecution.isRunning()) {
activeExecutions.add(jobExecution);
}
} else {
if (jsrJobOperator != null) {
// jobExecution = this.jobExecutionDao
// .getJobExecution(jsrJobOperator.start(jobName, jobParameters.toProperties()));
jobExecution = new JobExecution(jsrJobOperator.start(jobName, jobParameters.toProperties()));
} else {
throw new NoSuchJobException(String.format("Unable to find job %s to launch",
String.valueOf(jobName)));
}
}
return jobExecution;
}
I think the difficulty here comes from mixing scheduling with restartability. I would make each schedule execute a distinct job instance (for example by adding the run time as an identifying job parameter).
Now if a given schedule fails, it could be restarted separately until completion without affecting subsequent schedules. This can be done manually or programmtically in another scheduled method.
This is the solution I came up with after all the comments:
#Component
class JobScheduler extends JobSchedulerLauncher {
#Autowired
private Job job1;
#Scheduled(cron = "0 0/15 * * * ?")
public void launchJob1() throws Exception {
this.launch(this.job1);
}
}
public abstract class JobSchedulerLauncher {
#Autowired
private JobOperator jobOperator;
#Autowired
private JobExplorer jobExplorer;
public void launch(Job job) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
JobParametersInvalidException, NoSuchJobException, NoSuchJobExecutionException, JobExecutionNotRunningException, JobParametersNotFoundException, UnexpectedJobExecutionException {
// Get the last instance
final List<JobInstance> jobInstances = this.jobExplorer.findJobInstancesByJobName(job.getName(), 0, 1);
if (CollectionUtils.isNotEmpty(jobInstances)) {
// Get the last executions
final List<JobExecution> jobExecutions = this.jobExplorer.getJobExecutions(jobInstances.get(0));
if (CollectionUtils.isNotEmpty(jobExecutions)) {
final JobExecution lastJobExecution = jobExecutions.get(0);
if (lastJobExecution.isRunning()) {
this.jobOperator.stop(lastJobExecution.getId().longValue());
this.jobOperator.abandon(lastJobExecution.getId().longValue());
} else if (lastJobExecution.getExitStatus().equals(ExitStatus.FAILED) || lastJobExecution.getExitStatus().equals(ExitStatus.STOPPED)) {
this.jobOperator.restart(lastJobExecution.getId().longValue());
return;
}
}
}
this.jobOperator.startNextInstance(job.getName());
}
}
My job now uses an incrementer, based on this one https://docs.spring.io/spring-batch/docs/current/reference/html/job.html#JobParametersIncrementer:
#Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.incrementer(new CustomJobParameterIncrementor())
.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()
.from(this.step1()).on(STEP1_STATUS.READY.get()).to(this.step2())
.next(this.step3())
.end()
.build();
}
In my case my scheduler won't start 2 instances of the same job at the same time, so if I detect a running job in this code it means that the server restarted leaving the job with status STARTED, that's why I stop it and abandon it.

EntityManager in Transactional CDI bean

I have an EntityManager associated with my persistence unit (myPU).
I have the following code which represents a generic DataAccessObject which I want to use in order to execute tasks in a new transaction (requires-new).
This DataAccessObject gets injected into an EJB and its unique method gets invoked in a while loop.
Another EntityManager instance referencing the same persistence unit exists in the EJB.
I'm expecting that at every method invocation of my DataAccessObject instance, a new transaction gets created and committed (or rollbacked) according to the following code.
The problem is that i get a transaction required exception. What am i missing?
#Dependent
#ManagedBean
public class DataAccessObject {
private static final Logger logger = Logger.getLogger(DataAccessObject.class);
#PersistenceContext(unitName = "scheduler")
private EntityManager entityManager;
#Transactional(value = TxType.REQUIRES_NEW, rollbackOn = Exception.class)
public void executeInNewTransaction(TransactionalTask transactionalTask) throws TransactionalException {
Throwable exception = null;
try {
logger.debug(" A new transaction has been created for transactional task: \"", transactionalTask, "\".");
transactionalTask.onExecute(entityManager);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
exception = e;
} catch (ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolation = e.getConstraintViolations();
logger.error("Exception during bean validation:");
if (constraintViolation != null) {
for (ConstraintViolation<?> violation : constraintViolation) {
logger.error(String.format("%s=\"%s\" error: %s", violation.getPropertyPath(), violation.getInvalidValue(), violation.getMessage()));
}
}
exception = e;
} catch (Throwable e) {
exception = e;
} finally {
if (exception != null || transactionalTask.mustRollBack()) {
throw new TransactionRolledBackException("Transaction is being rolled back for transactional task: \"" + transactionalTask + "\".", exception);
} else {
logger.debug(" Transaction has been committed successfully for transactional task: \"", transactionalTask, "\".");
}
}
}
}

CXF-WS integration with spring boot (jhipster stack)

I try to integrate CXF WS to jhipster stack, so avoid xml configuration.
The first class to config service
#EnableWs
#Configuration
#AutoConfigureAfter(WebConfigurer.class)
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean dispatcherServlet() {
CXFServlet cxfServlet = new CXFServlet();
return new ServletRegistrationBean(cxfServlet, "/soap/*");
}
#Bean(name = "cxf")
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public Hello hello() {
return new HelloPortImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), hello());
endpoint.publish("/hello");
return endpoint;
}
}
The second file :
#WebService(targetNamespace = "http://service.ws.sample/", name = "Hello")
public interface Hello {
#WebResult(name = "return", targetNamespace = "")
#RequestWrapper(localName = "sayHello", targetNamespace = "http://service.ws.sample/", className = "com.orange.api.rfid.tacites.proxyauth.web.restWS.SayHello")
#WebMethod(action = "urn:SayHello")
#ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://service.ws.sample/", className = "com.orange.api.rfid.tacites.proxyauth.web.restWS.SayHelloResponse")
public java.lang.String sayHello(
#WebParam(name = "myname", targetNamespace = "")
java.lang.String myname
);
}
The third file
#javax.jws.WebService(
serviceName = "HelloService",
portName = "HelloPort",
targetNamespace = "http://service.ws.sample/",
endpointInterface = "com.orange.api.rfid.tacites.proxyauth.web.restWS.Hello")
public class HelloPortImpl implements Hello {
private static final Logger LOG = Logger.getLogger(HelloPortImpl.class.getName());
public java.lang.String sayHello(java.lang.String myname) {
LOG.info("Executing operation sayHello" + myname);
try {
return "Welcome to CXF Spring boot " + myname + "!!!";
} catch (java.lang.Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
}
In my logs when start spring boot, i have this line:
[DEBUG] com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator - Wrigin XML Schema for com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator#6a08fd54[http://service.ws.sample/=com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator$Namespace#76617add]
com.sun.xml.bind.v2.util.StackRecorder: null
at com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator.write(XmlSchemaGenerator.java:441) [jaxb-impl-2.2.jar:2.2]
The problem is Jhipster index.html is not found and in http://localhost:8080/soap/hello i have No binding operation info while invoking unknown method with params unknown
I think the cxf servlet kill first one servlet, how to configure to coexist both?
Regards
Try renaming your WebServiceConfig.dispatcherServlet method to something else as there is probably a bean with this name defined by Spring Boot that you're overriding.
To solve the issue, i add to WebConfigurer.java:
/**
* Initialize cxf - ws
*/
private void initCxf(ServletContext servletContext) {
log.debug("Initialize cxf - ws");
ServletRegistration.Dynamic cxfServlet = servletContext.addServlet("CxfWS", new CXFServlet());
cxfServlet.addMapping("/soap/*");
cxfServlet.setLoadOnStartup(3);
}
I've got this error when not specifying the proper wsdl name. Verify that the Soap Service instance uses a proper path to wsdl.

Quartz scheduler in not running in war

I am using quartz scheduler in gwt web application.My application structure is like below.
I have two project.One is gwt web application client project(for ui part) & other is java project for server side call.(for database interaction).In client project I put a server project for reference.While running I create a war from client and add a jar of server project to war folder.
Now I used scheduler at server side for some task to auto complete.While running it locally (with out war) scheduler working properly.
But while running war at jboss server scheduler is not running.
My all scheduler related code and Quartz.jar is at server side.There is no any reference of Quartz in client side project.is this the problem???
Here is my code for scheduler
public class QuartzJob implements Job {
public void execute(JobExecutionContext jobExecutionContext)
throws JobExecutionException {
JobDataMap map = jobExecutionContext.getJobDetail().getJobDataMap();
ActivityTransactionSettingsMap map2 = (ActivityTransactionSettingsMap) map
.get("task");
if (map2.getAutoCompleteDate() != null) {
WorkFlowFacade facade = new WorkFlowFacade();
facade.completeAutoCompleteTask(map2);
Scheduler scheduler=(Scheduler) map.get("scheduler");
try {
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDataMap map2 = new JobDataMap();
map2.put("task", actsMap);
map2.put("scheduler", scheduler);
JobDetail job = newJob(QuartzJob.class).withIdentity("job"+String.valueOf(actsMap.getId()))
.usingJobData(map2).build();
Trigger trigger = newTrigger().withIdentity("trigger"+String.valueOf(actsMap.getId()))
.startAt(actsMap.getAutoCompleteDate()).build();
scheduler.scheduleJob(job, trigger);
Or do I need to shift my scheduler related project at client side only??
I am not getting how to solve this.
Please help me out
For the scheduler to run , there should be something to kick start it . I am not sure how the process is happening but you could write this scheduler in a servlet
public class MySchedulerServlet extends GenericServlet {
private static final long serialVersionUID = 1477091380142883153L;
/**
* Constant to represent property for the cron expression.
*/
private static final String CRON_EXPRESSION = "0 0 0 ? * SUN";
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
// The Quartz Scheduler
Scheduler scheduler = null;
try {
// Initiate a Schedule Factory
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
// Retrieve a scheduler from schedule factory
scheduler = schedulerFactory.getScheduler();
// Initiate JobDetail with job name, job group and
// executable job class
JobDetail jobDetail = new JobDetail("RetryJob", "RetryGroup", QuartzJob.class);
// Initiate CronTrigger with its name and group name
CronTrigger cronTrigger = new CronTrigger("cronTrigger",
"triggerGroup");
// setup CronExpression
CronExpression cexp = new CronExpression(CRON_EXPRESSION);
// Assign the CronExpression to CronTrigger
cronTrigger.setCronExpression(cexp);
// schedule a job with JobDetail and Trigger
scheduler.scheduleJob(jobDetail, cronTrigger);
// start the scheduler
scheduler.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void service(ServletRequest serveletRequest,
ServletResponse servletResponse) throws ServletException, IOException {
}
}
and in your web.xml load sceduler on startup. This works for me.
<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-name>MySchedulerServlet </servlet-name>
<servlet-class>com.servlet.MySchedulerServlet </servlet-class>
<load-on-startup>2</load-on-startup>
I used thread in this case.
public class AutoCompleteTaskThread extends Thread {
private ActivityTransactionSettingsMap taskMap;
public AutoCompleteTaskThread(ActivityTransactionSettingsMap map) {
this.taskMap = map;
}
#Override
public void run() {
try {
new AutoCompleteTaskScheduler().ScheduleJob(taskMap);
} catch (Exception e) {
e.printStackTrace();
}
}
}
As below and in local machine it is working fine.but for jboss server it is not working.
I used an instance of AutoCompleteTaskThread class and called start method on this.
private void addAutoCompleteTask(ActivityTransactionSettingsMap newTask) {
AutoCompleteTaskThread thread = new AutoCompleteTaskThread(newTask);
thread.start();
}
Here for I started a thread for any new task for which I want to start new thread.

Implementing MDB Pool Listener in JBoss JMS

I've an application deployed in JBoss with multiple MDBs deployed using JBoss JMS implementation, each one with a different configuration of MDB Pool Size. I was looking forward to some kind of mechanism where we can have a listener on each MDB Pool size where we can check if at any point all instances from the MDB pool are getting utilized. This will help in analyzing and configuring the appropriate MDB pool size for each MDB.
We use Jamon to monitor instances of MDBs, like this:
#MessageDriven
#TransactionManagement(value = TransactionManagementType.CONTAINER)
#TransactionAttribute(value = TransactionAttributeType.REQUIRED)
#ResourceAdapter("wmq.jmsra.rar")
#AspectDomain("YourDomainName")
public class YourMessageDrivenBean implements MessageListener
{
// jamon package constant
protected static final String WB_ONMESSAGE = "wb.onMessage";
// instance counter
private static AtomicInteger counter = new AtomicInteger(0);
private int instanceIdentifier = 0;
#Resource
MessageDrivenContext ctx;
#Override
public void onMessage(Message message)
{
final Monitor monall = MonitorFactory.start(WB_ONMESSAGE);
final Monitor mon = MonitorFactory.start(WB_ONMESSAGE + "." + toString()
+ "; mdb instance identifier=" + instanceIdentifier);
try {
// process your message here
}
} catch (final Exception x) {
log.error("Error onMessage " + x.getMessage(), x);
ctx.setRollbackOnly();
} finally {
monall.stop();
mon.stop();
}
}
#PostConstruct
public void init()
{
instanceIdentifier = counter.incrementAndGet();
log.debug("constructed instance #" + instanceIdentifier);
}
}
You can then see in the Jamon-Monitor every created instance of your MDB.