use of org.apache.sling.event.impl.jobs.JobHandler in project sling by apache.
the class QueueJobCache method loadJobs.
/**
* Load the next N x numberOf(topics) jobs.
* @param topic The topic
* @param topicResource The parent resource of the jobs
* @return The cache which will be filled with the jobs.
*/
private List<JobImpl> loadJobs(final String queueName, final String topic, final Resource topicResource, final StatisticsManager statisticsManager) {
logger.debug("Loading jobs from topic {}", topic);
final List<JobImpl> list = new ArrayList<JobImpl>();
final AtomicBoolean scanTopic = new AtomicBoolean(false);
JobTopicTraverser.traverse(logger, topicResource, new JobTopicTraverser.JobCallback() {
@Override
public boolean handle(final JobImpl job) {
if (job.getProcessingStarted() == null && !job.hasReadErrors()) {
list.add(job);
statisticsManager.jobQueued(queueName, topic);
if (list.size() == maxPreloadLimit) {
scanTopic.set(true);
}
} else if (job.getProcessingStarted() != null) {
logger.debug("Ignoring job {} - processing already started.", job);
} else {
// error reading job
scanTopic.set(true);
if (job.isReadErrorRecoverable()) {
logger.debug("Ignoring job {} due to recoverable read errors.", job);
} else {
logger.debug("Failing job {} due to unrecoverable read errors.", job);
final JobHandler handler = new JobHandler(job, null, configuration);
handler.finished(JobState.ERROR, true, null);
}
}
return list.size() < maxPreloadLimit;
}
});
if (scanTopic.get()) {
synchronized (this.topicsWithNewJobs) {
this.topicsWithNewJobs.add(topic);
}
}
logger.debug("Caching {} jobs for topic {}", list.size(), topic);
return list;
}
use of org.apache.sling.event.impl.jobs.JobHandler in project sling by apache.
the class QueueJobCache method getNextJob.
/**
* Get the next job.
* This method is potentially called concurrently, and
* {@link #reschedule(String, JobHandler, StatisticsManager)} and {@link #handleNewTopics(Set)}
* can be called concurrently.
* @param jobConsumerManager The job consumer manager
* @param statisticsManager The statistics manager
* @param queue The queue
* @param doFull Whether to do a full scan
* @return The job handler or {@code null}.
*/
public JobHandler getNextJob(final JobConsumerManager jobConsumerManager, final StatisticsManager statisticsManager, final Queue queue, final boolean doFull) {
JobHandler handler = null;
if (!this.queueIsBlocked.get()) {
synchronized (this.cache) {
boolean retry;
do {
retry = false;
if (this.cache.isEmpty()) {
final Set<String> checkingTopics = new HashSet<String>();
synchronized (this.topicsWithNewJobs) {
checkingTopics.addAll(this.topicsWithNewJobs);
this.topicsWithNewJobs.clear();
}
if (doFull) {
checkingTopics.addAll(this.topics);
}
if (!checkingTopics.isEmpty()) {
this.loadJobs(queue.getName(), checkingTopics, statisticsManager);
}
}
if (!this.cache.isEmpty()) {
final JobImpl job = this.cache.remove(0);
final JobExecutor consumer = jobConsumerManager.getExecutor(job.getTopic());
handler = new JobHandler(job, consumer, this.configuration);
if (consumer != null) {
if (!handler.startProcessing(queue)) {
statisticsManager.jobDequeued(queue.getName(), handler.getJob().getTopic());
if (logger.isDebugEnabled()) {
logger.debug("Discarding removed job {}", Utility.toString(job));
}
handler = null;
retry = true;
}
} else {
statisticsManager.jobDequeued(queue.getName(), handler.getJob().getTopic());
// no consumer on this instance, assign to another instance
handler.reassign();
handler = null;
retry = true;
}
}
} while (handler == null && retry);
}
}
return handler;
}
use of org.apache.sling.event.impl.jobs.JobHandler in project sling by apache.
the class JobQueueImpl method startJobs.
/**
* Start the job queue.
* This method might be called concurrently, therefore we use a guard
*/
public void startJobs() {
if (this.startJobsGuard.compareAndSet(false, true)) {
// we start as many jobs in parallel as possible
while (this.running && !this.isOutdated.get() && !this.isSuspended() && this.available.tryAcquire()) {
boolean started = false;
this.lock.writeLock().lock();
try {
final JobHandler handler = this.cache.getNextJob(this.services.jobConsumerManager, this.services.statisticsManager, this, this.doFullCacheSearch.getAndSet(false));
if (handler != null) {
started = true;
this.threadPool.execute(new Runnable() {
@Override
public void run() {
// update thread priority and name
final Thread currentThread = Thread.currentThread();
final String oldName = currentThread.getName();
final int oldPriority = currentThread.getPriority();
currentThread.setName(oldName + "-" + handler.getJob().getQueueName() + "(" + handler.getJob().getTopic() + ")");
if (configuration.getThreadPriority() != null) {
switch(configuration.getThreadPriority()) {
case NORM:
currentThread.setPriority(Thread.NORM_PRIORITY);
break;
case MIN:
currentThread.setPriority(Thread.MIN_PRIORITY);
break;
case MAX:
currentThread.setPriority(Thread.MAX_PRIORITY);
break;
}
}
try {
startJob(handler);
} finally {
currentThread.setPriority(oldPriority);
currentThread.setName(oldName);
}
// and try to launch another job
startJobs();
}
});
} else {
// no job available, stop look
break;
}
} finally {
if (!started) {
this.available.release();
}
this.lock.writeLock().unlock();
}
}
this.startJobsGuard.set(false);
}
}
use of org.apache.sling.event.impl.jobs.JobHandler in project sling by apache.
the class JobQueueImpl method finishedJob.
/**
* Handle job finish and determine whether to reschedule or cancel the job
*/
private boolean finishedJob(final String jobId, final Job.JobState resultState, final boolean isAsync) {
this.services.configuration.getAuditLogger().debug("FINISHED {} : {}", resultState, jobId);
this.logger.debug("Received finish for job {}, resultState={}", jobId, resultState);
// get job handler
final JobHandler handler;
// let's remove the event from our processing list
synchronized (this.processingJobsLists) {
handler = this.processingJobsLists.remove(jobId);
}
if (!this.running) {
this.logger.warn("Queue is not running anymore. Discarding finish for {}", jobId);
return false;
}
if (handler == null) {
this.logger.warn("This job has never been started by this queue: {}", jobId);
return false;
}
// handle the rescheduling of the job
final RescheduleInfo rescheduleInfo = this.handleReschedule(handler, resultState);
if (!rescheduleInfo.reschedule) {
// we keep cancelled jobs and succeeded jobs if the queue is configured like this.
final boolean keepJobs = rescheduleInfo.state != Job.JobState.SUCCEEDED || this.configuration.isKeepJobs();
handler.finished(rescheduleInfo.state, keepJobs, rescheduleInfo.processingTime);
} else {
this.reschedule(handler);
}
// update statistics
this.services.statisticsManager.jobEnded(this.queueName, handler.getJob().getTopic(), rescheduleInfo.finalState, rescheduleInfo.processingTime);
// send notification
NotificationUtility.sendNotification(this.services.eventAdmin, rescheduleInfo.finalState.getTopic(), handler.getJob(), rescheduleInfo.processingTime);
return rescheduleInfo.reschedule;
}
use of org.apache.sling.event.impl.jobs.JobHandler in project sling by apache.
the class QueueManager method restart.
/**
* Outdate all queues.
*/
private void restart() {
// let's rename/close all queues and clear them
synchronized (queuesLock) {
final List<JobQueueImpl> queues = new ArrayList<>(this.queues.values());
for (final JobQueueImpl queue : queues) {
this.outdateQueue(queue);
}
}
// check if we're still active
final JobManagerConfiguration config = this.configuration;
if (config != null) {
final List<Job> rescheduleList = this.configuration.clearJobRetryList();
for (final Job j : rescheduleList) {
final JobHandler jh = new JobHandler((JobImpl) j, null, this.configuration);
jh.reschedule();
}
}
}
Aggregations