Add support for memory-only jobs.

This commit is contained in:
Greyson Parrelli
2020-06-25 05:32:36 -07:00
parent 2001fa86cf
commit 87a59b6a9b
13 changed files with 314 additions and 133 deletions

View File

@@ -245,6 +245,7 @@ public abstract class Job {
private final String queue;
private final List<String> constraintKeys;
private final Data inputData;
private final boolean memoryOnly;
private Parameters(@NonNull String id,
long createTime,
@@ -254,7 +255,8 @@ public abstract class Job {
int maxInstances,
@Nullable String queue,
@NonNull List<String> constraintKeys,
@Nullable Data inputData)
@Nullable Data inputData,
boolean memoryOnly)
{
this.id = id;
this.createTime = createTime;
@@ -265,6 +267,7 @@ public abstract class Job {
this.queue = queue;
this.constraintKeys = constraintKeys;
this.inputData = inputData;
this.memoryOnly = memoryOnly;
}
@NonNull String getId() {
@@ -303,8 +306,12 @@ public abstract class Job {
return inputData;
}
boolean isMemoryOnly() {
return memoryOnly;
}
public Builder toBuilder() {
return new Builder(id, createTime, maxBackoff, lifespan, maxAttempts, maxInstances, queue, constraintKeys, inputData);
return new Builder(id, createTime, maxBackoff, lifespan, maxAttempts, maxInstances, queue, constraintKeys, inputData, memoryOnly);
}
@@ -319,13 +326,14 @@ public abstract class Job {
private String queue;
private List<String> constraintKeys;
private Data inputData;
private boolean memoryOnly;
public Builder() {
this(UUID.randomUUID().toString());
}
Builder(@NonNull String id) {
this(id, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(30), IMMORTAL, 1, UNLIMITED, null, new LinkedList<>(), null);
this(id, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(30), IMMORTAL, 1, UNLIMITED, null, new LinkedList<>(), null, false);
}
private Builder(@NonNull String id,
@@ -336,7 +344,8 @@ public abstract class Job {
int maxInstances,
@Nullable String queue,
@NonNull List<String> constraintKeys,
@Nullable Data inputData)
@Nullable Data inputData,
boolean memoryOnly)
{
this.id = id;
this.createTime = createTime;
@@ -347,6 +356,7 @@ public abstract class Job {
this.queue = queue;
this.constraintKeys = constraintKeys;
this.inputData = inputData;
this.memoryOnly = memoryOnly;
}
/** Should only be invoked by {@link JobController} */
@@ -424,6 +434,17 @@ public abstract class Job {
return this;
}
/**
* Specify whether or not you want this job to only live in memory. If true, this job will
* *not* survive application death. This defaults to false, and should be used with care.
*
* Defaults to false.
*/
public @NonNull Builder setMemoryOnly(boolean memoryOnly) {
this.memoryOnly = memoryOnly;
return this;
}
/**
* Sets the input data that will be made availabe to the job when it is run.
* Should only be set by {@link JobController}.
@@ -434,7 +455,7 @@ public abstract class Job {
}
public @NonNull Parameters build() {
return new Parameters(id, createTime, lifespan, maxAttempts, maxBackoff, maxInstances, queue, constraintKeys, inputData);
return new Parameters(id, createTime, lifespan, maxAttempts, maxBackoff, maxInstances, queue, constraintKeys, inputData, memoryOnly);
}
}
}

View File

@@ -354,14 +354,20 @@ class JobController {
job.getParameters().getMaxInstances(),
dataSerializer.serialize(job.serialize()),
null,
false);
false,
job.getParameters().isMemoryOnly());
List<ConstraintSpec> constraintSpecs = Stream.of(job.getParameters().getConstraintKeys())
.map(key -> new ConstraintSpec(jobSpec.getId(), key))
.map(key -> new ConstraintSpec(jobSpec.getId(), key, jobSpec.isMemoryOnly()))
.toList();
List<DependencySpec> dependencySpecs = Stream.of(dependsOn)
.map(depends -> new DependencySpec(job.getId(), depends))
.map(depends -> {
JobSpec dependsOnJobSpec = jobStorage.getJobSpec(depends);
boolean memoryOnly = job.getParameters().isMemoryOnly() || (dependsOnJobSpec != null && dependsOnJobSpec.isMemoryOnly());
return new DependencySpec(job.getId(), depends, memoryOnly);
})
.toList();
return new FullSpec(jobSpec, constraintSpecs, dependencySpecs);
@@ -371,7 +377,7 @@ class JobController {
private void scheduleJobs(@NonNull List<Job> jobs) {
for (Job job : jobs) {
List<Constraint> constraints = Stream.of(job.getParameters().getConstraintKeys())
.map(key -> new ConstraintSpec(job.getId(), key))
.map(key -> new ConstraintSpec(job.getId(), key, job.getParameters().isMemoryOnly()))
.map(ConstraintSpec::getFactoryKey)
.map(constraintInstantiator::instantiate)
.toList();
@@ -460,7 +466,8 @@ class JobController {
jobSpec.getMaxInstances(),
jobSpec.getSerializedData(),
dataSerializer.serialize(inputData),
jobSpec.isRunning());
jobSpec.isRunning(),
jobSpec.isMemoryOnly());
}
interface Callback {

View File

@@ -76,7 +76,8 @@ public class JobMigrator {
jobSpec.getMaxInstances(),
dataSerializer.serialize(updatedJobData.getData()),
jobSpec.getSerializedInputData(),
jobSpec.isRunning());
jobSpec.isRunning(),
jobSpec.isMemoryOnly());
iter.set(updatedJobSpec);
}

View File

@@ -6,12 +6,14 @@ import java.util.Objects;
public final class ConstraintSpec {
private final String jobSpecId;
private final String factoryKey;
private final String jobSpecId;
private final String factoryKey;
private final boolean memoryOnly;
public ConstraintSpec(@NonNull String jobSpecId, @NonNull String factoryKey) {
public ConstraintSpec(@NonNull String jobSpecId, @NonNull String factoryKey, boolean memoryOnly) {
this.jobSpecId = jobSpecId;
this.factoryKey = factoryKey;
this.memoryOnly = memoryOnly;
}
public String getJobSpecId() {
@@ -22,22 +24,27 @@ public final class ConstraintSpec {
return factoryKey;
}
public boolean isMemoryOnly() {
return memoryOnly;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConstraintSpec that = (ConstraintSpec) o;
return Objects.equals(jobSpecId, that.jobSpecId) &&
Objects.equals(factoryKey, that.factoryKey);
return Objects.equals(jobSpecId, that.jobSpecId) &&
Objects.equals(factoryKey, that.factoryKey) &&
memoryOnly == that.memoryOnly;
}
@Override
public int hashCode() {
return Objects.hash(jobSpecId, factoryKey);
return Objects.hash(jobSpecId, factoryKey, memoryOnly);
}
@Override
public @NonNull String toString() {
return String.format("jobSpecId: JOB::%s | factoryKey: %s", jobSpecId, factoryKey);
return String.format("jobSpecId: JOB::%s | factoryKey: %s | memoryOnly: %b", jobSpecId, factoryKey, memoryOnly);
}
}

View File

@@ -6,12 +6,14 @@ import java.util.Objects;
public final class DependencySpec {
private final String jobId;
private final String dependsOnJobId;
private final String jobId;
private final String dependsOnJobId;
private final boolean memoryOnly;
public DependencySpec(@NonNull String jobId, @NonNull String dependsOnJobId) {
public DependencySpec(@NonNull String jobId, @NonNull String dependsOnJobId, boolean memoryOnly) {
this.jobId = jobId;
this.dependsOnJobId = dependsOnJobId;
this.memoryOnly = memoryOnly;
}
public @NonNull String getJobId() {
@@ -22,22 +24,27 @@ public final class DependencySpec {
return dependsOnJobId;
}
public boolean isMemoryOnly() {
return memoryOnly;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DependencySpec that = (DependencySpec) o;
return Objects.equals(jobId, that.jobId) &&
Objects.equals(dependsOnJobId, that.dependsOnJobId);
return Objects.equals(jobId, that.jobId) &&
Objects.equals(dependsOnJobId, that.dependsOnJobId) &&
memoryOnly == that.memoryOnly;
}
@Override
public int hashCode() {
return Objects.hash(jobId, dependsOnJobId);
return Objects.hash(jobId, dependsOnJobId, memoryOnly);
}
@Override
public @NonNull String toString() {
return String.format("jobSpecId: JOB::%s | dependsOnJobSpecId: JOB::%s", jobId, dependsOnJobId);
return String.format("jobSpecId: JOB::%s | dependsOnJobSpecId: JOB::%s | memoryOnly: %b", jobId, dependsOnJobId, memoryOnly);
}
}

View File

@@ -32,6 +32,9 @@ public final class FullSpec {
return dependencySpecs;
}
public boolean isMemoryOnly() {
return jobSpec.isMemoryOnly();
}
@Override
public boolean equals(Object o) {

View File

@@ -21,6 +21,7 @@ public final class JobSpec {
private final String serializedData;
private final String serializedInputData;
private final boolean isRunning;
private final boolean memoryOnly;
public JobSpec(@NonNull String id,
@NonNull String factoryKey,
@@ -34,7 +35,8 @@ public final class JobSpec {
int maxInstances,
@NonNull String serializedData,
@Nullable String serializedInputData,
boolean isRunning)
boolean isRunning,
boolean memoryOnly)
{
this.id = id;
this.factoryKey = factoryKey;
@@ -49,6 +51,7 @@ public final class JobSpec {
this.serializedData = serializedData;
this.serializedInputData = serializedInputData;
this.isRunning = isRunning;
this.memoryOnly = memoryOnly;
}
public @NonNull String getId() {
@@ -103,6 +106,10 @@ public final class JobSpec {
return isRunning;
}
public boolean isMemoryOnly() {
return memoryOnly;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -116,6 +123,7 @@ public final class JobSpec {
lifespan == jobSpec.lifespan &&
maxInstances == jobSpec.maxInstances &&
isRunning == jobSpec.isRunning &&
memoryOnly == jobSpec.memoryOnly &&
Objects.equals(id, jobSpec.id) &&
Objects.equals(factoryKey, jobSpec.factoryKey) &&
Objects.equals(queueKey, jobSpec.queueKey) &&
@@ -125,13 +133,13 @@ public final class JobSpec {
@Override
public int hashCode() {
return Objects.hash(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, lifespan, maxInstances, serializedData, serializedInputData, isRunning);
return Objects.hash(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, lifespan, maxInstances, serializedData, serializedInputData, isRunning, memoryOnly);
}
@SuppressLint("DefaultLocale")
@Override
public @NonNull String toString() {
return String.format("id: JOB::%s | factoryKey: %s | queueKey: %s | createTime: %d | nextRunAttemptTime: %d | runAttempt: %d | maxAttempts: %d | maxBackoff: %d | maxInstances: %d | lifespan: %d | isRunning: %b",
id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, maxInstances, lifespan, isRunning);
return String.format("id: JOB::%s | factoryKey: %s | queueKey: %s | createTime: %d | nextRunAttemptTime: %d | runAttempt: %d | maxAttempts: %d | maxBackoff: %d | maxInstances: %d | lifespan: %d | isRunning: %b | memoryOnly: %b",
id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, maxInstances, lifespan, isRunning, memoryOnly);
}
}

View File

@@ -69,12 +69,13 @@ final class WorkManagerDatabase extends SQLiteOpenHelper {
Job.Parameters.UNLIMITED,
dataSerializer.serialize(DataMigrator.convert(data)),
null,
false,
false);
if (cursor.getInt(cursor.getColumnIndexOrThrow("required_network_type")) != 0) {
constraints.add(new ConstraintSpec(id, NetworkConstraint.KEY));
constraints.add(new ConstraintSpec(id, NetworkConstraint.KEY, false));
}
fullSpecs.add(new FullSpec(jobSpec, constraints, Collections.emptyList()));