mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 17:58:34 +00:00
Allow RuntimeExceptions thrown by Jobs to crash.
This commit is contained in:
parent
e8e80e5d05
commit
17400020b7
@ -125,8 +125,59 @@ public abstract class Job {
|
|||||||
@NonNull T create(@NonNull Parameters parameters, @NonNull Data data);
|
@NonNull T create(@NonNull Parameters parameters, @NonNull Data data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Result {
|
public static final class Result {
|
||||||
SUCCESS, FAILURE, RETRY
|
|
||||||
|
private static final Result SUCCESS = new Result(ResultType.SUCCESS, null);
|
||||||
|
private static final Result RETRY = new Result(ResultType.RETRY, null);
|
||||||
|
private static final Result FAILURE = new Result(ResultType.FAILURE, null);
|
||||||
|
|
||||||
|
private final ResultType resultType;
|
||||||
|
private final RuntimeException runtimeException;
|
||||||
|
|
||||||
|
private Result(@NonNull ResultType resultType, @Nullable RuntimeException runtimeException) {
|
||||||
|
this.resultType = resultType;
|
||||||
|
this.runtimeException = runtimeException;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Job completed successfully. */
|
||||||
|
public static Result success() {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Job did not complete successfully, but it can be retried later. */
|
||||||
|
public static Result retry() {
|
||||||
|
return RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Job did not complete successfully and should not be tried again. Dependent jobs will also be failed.*/
|
||||||
|
public static Result failure() {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Same as {@link #failure()}, except the app should also crash with the provided exception. */
|
||||||
|
public static Result fatalFailure(@NonNull RuntimeException runtimeException) {
|
||||||
|
return new Result(ResultType.FAILURE, runtimeException);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSuccess() {
|
||||||
|
return resultType == ResultType.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isRetry() {
|
||||||
|
return resultType == ResultType.RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFailure() {
|
||||||
|
return resultType == ResultType.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable RuntimeException getException() {
|
||||||
|
return runtimeException;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ResultType {
|
||||||
|
SUCCESS, FAILURE, RETRY
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Parameters {
|
public static final class Parameters {
|
||||||
|
@ -12,6 +12,14 @@ import org.thoughtcrime.securesms.util.WakeLockUtil;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thread that constantly checks for available {@link Job}s owned by the {@link JobController}.
|
||||||
|
* When one is available, this class will execute it and call the appropriate methods on
|
||||||
|
* {@link JobController} based on the result.
|
||||||
|
*
|
||||||
|
* {@link JobRunner} and {@link JobController} were written such that you should be able to have
|
||||||
|
* N concurrent {@link JobRunner}s operating over the same {@link JobController}.
|
||||||
|
*/
|
||||||
class JobRunner extends Thread {
|
class JobRunner extends Thread {
|
||||||
|
|
||||||
private static final String TAG = JobRunner.class.getSimpleName();
|
private static final String TAG = JobRunner.class.getSimpleName();
|
||||||
@ -32,25 +40,28 @@ class JobRunner extends Thread {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void run() {
|
public synchronized void run() {
|
||||||
|
//noinspection InfiniteLoopStatement
|
||||||
while (true) {
|
while (true) {
|
||||||
Job job = jobController.pullNextEligibleJobForExecution();
|
Job job = jobController.pullNextEligibleJobForExecution();
|
||||||
Job.Result result = run(job);
|
Job.Result result = run(job);
|
||||||
|
|
||||||
jobController.onJobFinished(job);
|
jobController.onJobFinished(job);
|
||||||
|
|
||||||
switch (result) {
|
if (result.isSuccess()) {
|
||||||
case SUCCESS:
|
jobController.onSuccess(job);
|
||||||
jobController.onSuccess(job);
|
} else if (result.isRetry()) {
|
||||||
break;
|
jobController.onRetry(job);
|
||||||
case RETRY:
|
job.onRetry();
|
||||||
jobController.onRetry(job);
|
} else if (result.isFailure()) {
|
||||||
job.onRetry();
|
List<Job> dependents = jobController.onFailure(job);
|
||||||
break;
|
job.onCanceled();
|
||||||
case FAILURE:
|
Stream.of(dependents).forEach(Job::onCanceled);
|
||||||
List<Job> dependents = jobController.onFailure(job);
|
|
||||||
job.onCanceled();
|
if (result.getException() != null) {
|
||||||
Stream.of(dependents).forEach(Job::onCanceled);
|
throw result.getException();
|
||||||
break;
|
}
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Invalid job result!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +71,7 @@ class JobRunner extends Thread {
|
|||||||
|
|
||||||
if (isJobExpired(job)) {
|
if (isJobExpired(job)) {
|
||||||
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing after surpassing its lifespan."));
|
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing after surpassing its lifespan."));
|
||||||
return Job.Result.FAILURE;
|
return Job.Result.failure();
|
||||||
}
|
}
|
||||||
|
|
||||||
Job.Result result = null;
|
Job.Result result = null;
|
||||||
@ -71,7 +82,7 @@ class JobRunner extends Thread {
|
|||||||
result = job.run();
|
result = job.run();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing due to an unexpected exception."), e);
|
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing due to an unexpected exception."), e);
|
||||||
return Job.Result.FAILURE;
|
return Job.Result.failure();
|
||||||
} finally {
|
} finally {
|
||||||
if (wakeLock != null) {
|
if (wakeLock != null) {
|
||||||
WakeLockUtil.release(wakeLock, job.getId());
|
WakeLockUtil.release(wakeLock, job.getId());
|
||||||
@ -80,11 +91,12 @@ class JobRunner extends Thread {
|
|||||||
|
|
||||||
printResult(job, result);
|
printResult(job, result);
|
||||||
|
|
||||||
if (result == Job.Result.RETRY && job.getRunAttempt() + 1 >= job.getParameters().getMaxAttempts() &&
|
if (result.isRetry() &&
|
||||||
|
job.getRunAttempt() + 1 >= job.getParameters().getMaxAttempts() &&
|
||||||
job.getParameters().getMaxAttempts() != Job.Parameters.UNLIMITED)
|
job.getParameters().getMaxAttempts() != Job.Parameters.UNLIMITED)
|
||||||
{
|
{
|
||||||
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing after surpassing its max number of attempts."));
|
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing after surpassing its max number of attempts."));
|
||||||
return Job.Result.FAILURE;
|
return Job.Result.failure();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -101,7 +113,9 @@ class JobRunner extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void printResult(@NonNull Job job, @NonNull Job.Result result) {
|
private void printResult(@NonNull Job job, @NonNull Job.Result result) {
|
||||||
if (result == Job.Result.FAILURE) {
|
if (result.getException() != null) {
|
||||||
|
Log.e(TAG, JobLogger.format(job, String.valueOf(id), "Job failed with a fatal exception. Crash imminent."));
|
||||||
|
} else if (result.isFailure()) {
|
||||||
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Job failed."));
|
Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Job failed."));
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, JobLogger.format(job, String.valueOf(id), "Job finished with result: " + result));
|
Log.i(TAG, JobLogger.format(job, String.valueOf(id), "Job finished with result: " + result));
|
||||||
|
@ -19,14 +19,17 @@ public abstract class BaseJob extends Job {
|
|||||||
public @NonNull Result run() {
|
public @NonNull Result run() {
|
||||||
try {
|
try {
|
||||||
onRun();
|
onRun();
|
||||||
return Result.SUCCESS;
|
return Result.success();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e(TAG, "Encountered a fatal exception. Crash imminent.", e);
|
||||||
|
return Result.fatalFailure(e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (onShouldRetry(e)) {
|
if (onShouldRetry(e)) {
|
||||||
Log.i(TAG, JobLogger.format(this, "Encountered a retryable exception."), e);
|
Log.i(TAG, JobLogger.format(this, "Encountered a retryable exception."), e);
|
||||||
return Result.RETRY;
|
return Result.retry();
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, JobLogger.format(this, "Encountered a failing exception."), e);
|
Log.w(TAG, JobLogger.format(this, "Encountered a failing exception."), e);
|
||||||
return Result.FAILURE;
|
return Result.failure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user