package com.indeed.proctor.webapp.controllers;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.indeed.proctor.webapp.util.threads.LogOnUncaughtExceptionHandler;
import com.indeed.util.varexport.VarExporter;
import com.indeed.proctor.webapp.util.ThreadPoolExecutorVarExports;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class BackgroundJobManager {
private final List<BackgroundJob> backgroundJobs = Lists.newLinkedList();
private final ExecutorService service;
private final Map<Long, BackgroundJob> history = new MapMaker()
.softValues()
.makeMap();
private final AtomicLong lastId = new AtomicLong(0);
public BackgroundJobManager() {
this(initThreadPool());
}
public BackgroundJobManager(final ThreadPoolExecutor executor) {
final VarExporter exporter = VarExporter.forNamespace(getClass().getSimpleName());
exporter.export(new ThreadPoolExecutorVarExports(executor), "pool-");
this.service = executor;
}
private static ThreadPoolExecutor initThreadPool() {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(BackgroundJobManager.class.getSimpleName() + "-Thread-%d")
.setUncaughtExceptionHandler(new LogOnUncaughtExceptionHandler())
.build();
return new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
}
public <T> void submit(BackgroundJob<T> job) {
long id = lastId.incrementAndGet();
job.setId(id);
Future<T> future = service.submit(job);
job.setFuture(future);
backgroundJobs.add(job);
history.put(id, job);
}
public List<BackgroundJob> getRecentJobs() {
List<BackgroundJob> recent = Lists.newArrayListWithCapacity(backgroundJobs.size());
ListIterator<BackgroundJob> jobs = backgroundJobs.listIterator();
while (jobs.hasNext()) {
BackgroundJob job = jobs.next();
recent.add(job); // inactive jobs get to be returned once...
if (job.getFuture().isDone() || job.getFuture().isCancelled()) {
jobs.remove();
}
}
return recent;
}
@SuppressWarnings("unchecked")
public <T> BackgroundJob<T> getJobForId(long id) {
return history.get(id);
}
}