Skip to content

Commit eb09552

Browse files
committed
job status implementation #18
1 parent a9567ff commit eb09552

File tree

4 files changed

+88
-7
lines changed

4 files changed

+88
-7
lines changed

jobqueue/src/com/path/android/jobqueue/JobManager.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,41 @@ private void reAddJob(JobHolder jobHolder) {
304304
}
305305

306306
/**
307-
* returns the current status of a {@link Job}
307+
* Returns the current status of a {@link Job}.
308+
* <p>
309+
* You should not call this method on UI thread because it may make a db request.
310+
* </p>
308311
* @param id the ID, returned by the addJob method
309312
* @param isPersistent Jobs are added to different queues depending on if they are persistent or not. This is necessary
310313
* because each queue has independent id sets.
311314
* @return
312315
*/
313316
public JobStatus getJobStatus(long id, boolean isPersistent) {
314-
return null;
317+
if(jobConsumerExecutor.isRunning(id, isPersistent)) {
318+
return JobStatus.RUNNING;
319+
}
320+
JobHolder holder;
321+
if(isPersistent) {
322+
synchronized (persistentJobQueue) {
323+
holder = persistentJobQueue.findJobById(id);
324+
}
325+
} else {
326+
synchronized (nonPersistentJobQueue) {
327+
holder = nonPersistentJobQueue.findJobById(id);
328+
}
329+
}
330+
if(holder == null) {
331+
return JobStatus.UNKNOWN;
332+
}
333+
boolean network = hasNetwork();
334+
if(holder.requiresNetwork() && !network) {
335+
return JobStatus.WAITING_NOT_READY;
336+
}
337+
if(holder.getDelayUntilNs() > System.nanoTime()) {
338+
return JobStatus.WAITING_NOT_READY;
339+
}
340+
341+
return JobStatus.WAITING_READY;
315342
}
316343

317344
private void removeJob(JobHolder jobHolder) {

jobqueue/src/com/path/android/jobqueue/JobStatus.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public enum JobStatus {
99
* As of v 1.1, this might be:
1010
* <ul>
1111
* <li>Job requires network but there is no available network connection</li>
12+
* <li>Job is delayed. We are waiting for the time to pass</li>
1213
* </ul>
1314
*/
1415
WAITING_NOT_READY,

jobqueue/src/com/path/android/jobqueue/executor/JobConsumerExecutor.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.path.android.jobqueue.config.Configuration;
77
import com.path.android.jobqueue.log.JqLog;
88

9+
import java.util.concurrent.ConcurrentHashMap;
910
import java.util.concurrent.TimeUnit;
1011
import java.util.concurrent.atomic.AtomicInteger;
1112

@@ -21,7 +22,8 @@ public class JobConsumerExecutor {
2122
private final Contract contract;
2223
private final int keepAliveSeconds;
2324
private final AtomicInteger activeConsumerCount = new AtomicInteger(0);
24-
private final AtomicInteger runningJobCount = new AtomicInteger(0);
25+
// key : id + (isPersistent)
26+
private final ConcurrentHashMap<String, JobHolder> runningJobHolders;
2527

2628

2729
public JobConsumerExecutor(Configuration config, Contract contract) {
@@ -31,6 +33,7 @@ public JobConsumerExecutor(Configuration config, Contract contract) {
3133
this.keepAliveSeconds = config.getConsumerKeepAlive();
3234
this.contract = contract;
3335
threadGroup = new ThreadGroup("JobConsumers");
36+
runningJobHolders = new ConcurrentHashMap<String, JobHolder>();
3437
}
3538

3639
/**
@@ -92,17 +95,43 @@ private boolean isAboveLoadFactor(boolean inConsumerThread) {
9295
int consumerCnt = activeConsumerCount.intValue() - (inConsumerThread ? 1 : 0);
9396
boolean res =
9497
consumerCnt < minConsumerSize ||
95-
consumerCnt * loadFactor < contract.countRemainingReadyJobs() + runningJobCount.get();
98+
consumerCnt * loadFactor < contract.countRemainingReadyJobs() + runningJobHolders.size();
9699
if(JqLog.isDebugEnabled()) {
97100
JqLog.d("%s: load factor check. %s = (%d < %d)|| (%d * %d < %d + %d). consumer thread: %s", Thread.currentThread().getName(), res,
98101
consumerCnt, minConsumerSize,
99-
consumerCnt, loadFactor, contract.countRemainingReadyJobs(), runningJobCount.get(), inConsumerThread);
102+
consumerCnt, loadFactor, contract.countRemainingReadyJobs(), runningJobHolders.size(), inConsumerThread);
100103
}
101104
return res;
102105
}
103106

104107
}
105108

109+
private void onBeforeRun(JobHolder jobHolder) {
110+
runningJobHolders.put(createrunningJobHolderKey(jobHolder), jobHolder);
111+
}
112+
113+
private void onAfterRun(JobHolder jobHolder) {
114+
runningJobHolders.remove(createrunningJobHolderKey(jobHolder));
115+
}
116+
117+
private String createrunningJobHolderKey(JobHolder jobHolder) {
118+
return createrunningJobHolderKey(jobHolder.getId(), jobHolder.getBaseJob().isPersistent());
119+
}
120+
121+
private String createrunningJobHolderKey(long id, boolean isPersistent) {
122+
return id + "_" + (isPersistent ? "t" : "f");
123+
}
124+
125+
/**
126+
* returns true if job is currently handled by one of the executor threads
127+
* @param id id of the job
128+
* @param persistent boolean flag to distinguish id conflicts
129+
* @return true if job is currently handled here
130+
*/
131+
public boolean isRunning(long id, boolean persistent) {
132+
return runningJobHolders.containsKey(createrunningJobHolderKey(id, persistent));
133+
}
134+
106135
/**
107136
* contract between the {@link JobManager} and {@link JobConsumerExecutor}
108137
*/
@@ -168,13 +197,13 @@ public void run() {
168197
do {
169198
nextJob = contract.isRunning() ? contract.getNextJob(executor.keepAliveSeconds, TimeUnit.SECONDS) : null;
170199
if (nextJob != null) {
171-
executor.runningJobCount.incrementAndGet();
200+
executor.onBeforeRun(nextJob);
172201
if (nextJob.safeRun(nextJob.getRunCount())) {
173202
contract.removeJob(nextJob);
174203
} else {
175204
contract.insertOrReplace(nextJob);
176205
}
177-
executor.runningJobCount.decrementAndGet();
206+
executor.onAfterRun(nextJob);
178207
}
179208
} while (nextJob != null);
180209
} finally {

jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,29 @@ public void testJobStatus() throws InterruptedException {
9191
//after all jobs finish, state should be unknown
9292
assertThat("all jobs finished, states should be unknown", jobManager.getJobStatus(ids[i], jobs[i].isPersistent()), is(JobStatus.UNKNOWN));
9393
}
94+
final long SHORT_SLEEP = 1000;
95+
Job[] delayedJobs = new Job[]{
96+
new DummyJob(new Params(0).delayInMs(SHORT_SLEEP)),
97+
new DummyJob(new Params(0).delayInMs(SHORT_SLEEP).persist()),
98+
new DummyJob(new Params(0).delayInMs(SHORT_SLEEP * 10)),
99+
new DummyJob(new Params(0).delayInMs(SHORT_SLEEP * 10).persist())};
100+
long[] delayedIds = new long[delayedJobs.length];
101+
for(int i = 0; i < delayedJobs.length; i ++) {
102+
delayedIds[i] = jobManager.addJob(delayedJobs[i]);
103+
}
104+
105+
for(int i = 0; i < delayedJobs.length; i ++) {
106+
assertThat("delayed job(" + i + ") should receive not ready status", jobManager.getJobStatus(delayedIds[i], delayedJobs[i].isPersistent()), is(JobStatus.WAITING_NOT_READY));
107+
}
108+
jobManager.stop();
109+
//sleep
110+
Thread.sleep(SHORT_SLEEP * 2);
111+
for(int i = 0; i < delayedJobs.length; i ++) {
112+
if(delayedJobs[i].getDelayInMs() == SHORT_SLEEP) {
113+
assertThat("when enough time passes, delayed jobs should move to ready state", jobManager.getJobStatus(delayedIds[i], delayedJobs[i].isPersistent()), is(JobStatus.WAITING_READY));
114+
} else {
115+
assertThat("delayed job should receive not ready status until their time comes", jobManager.getJobStatus(delayedIds[i], delayedJobs[i].isPersistent()), is(JobStatus.WAITING_NOT_READY));
116+
}
117+
}
94118
}
95119
}

0 commit comments

Comments
 (0)