/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*/
package com.sun.sgs.impl.kernel.schedule;
import com.sun.sgs.app.ExceptionRetryStatus;
import com.sun.sgs.impl.sharedutil.LoggerWrapper;
import com.sun.sgs.impl.sharedutil.PropertiesWrapper;
import com.sun.sgs.kernel.schedule.ScheduledTask;
import com.sun.sgs.kernel.schedule.SchedulerRetryAction;
import com.sun.sgs.kernel.schedule.SchedulerRetryPolicy;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A simple retry "in place" {@code SchedulerRetryPolicy}. This
* {@code SchedulerRetryPolicy} always causes a task that throws a
* retryable exception to retry immediately. This class supports the following
* configuration properties:
*
* <dl style="margin-left: 1em">
*
* <dt> <i>Property:</i> <code><b>
* {@value #RETRY_WARNING_THRESHOLD_PROPERTY}
* </b></code><br>
* <i>Default:</i> {@value #DEFAULT_RETRY_WARNING_THRESHOLD}
*
* <dd style="padding-top: .5em">If a task has been retried a multiple of
* times equal to the value of this property, then a {@code WARNING}
* message will be logged as feedback to the user. This value must be
* greater than or equal to {@code 1}.
*
* </dl> <p>
*/
public class ImmediateRetryPolicy implements SchedulerRetryPolicy {
// logger for this class
private static final LoggerWrapper logger =
new LoggerWrapper(Logger.getLogger(ImmediateRetryPolicy.
class.getName()));
/**
* The property used to define the retry count threshold to use before
* printing a WARNING message.
*/
static final String RETRY_WARNING_THRESHOLD_PROPERTY =
"com.sun.sgs.impl.kernel.schedule.retry.warning.threshold";
/**
* The default retry warning threshold
*/
static final int DEFAULT_RETRY_WARNING_THRESHOLD = 25;
// the task retry count at which a warning should be printed
private final int retryWarningThreshold;
/**
* Constructs an {@code ImmediateRetryPolicy}.
*
* @param properties the system properties available
*/
public ImmediateRetryPolicy(Properties properties) {
PropertiesWrapper wrappedProps = new PropertiesWrapper(properties);
this.retryWarningThreshold = wrappedProps.getIntProperty(
RETRY_WARNING_THRESHOLD_PROPERTY,
DEFAULT_RETRY_WARNING_THRESHOLD,
1, Integer.MAX_VALUE);
logger.log(Level.CONFIG,
"Created ImmediateRetryPolicy with properties:" +
"\n " + RETRY_WARNING_THRESHOLD_PROPERTY + "=" +
retryWarningThreshold);
}
/** {@inheritDoc} */
public SchedulerRetryAction getRetryAction(ScheduledTask task) {
// null task is not allowed
if (task == null) {
throw new IllegalArgumentException("task cannot be null");
}
// result cannot be null
Throwable result = task.getLastFailure();
if (result == null) {
throw new IllegalStateException("task's last failure " +
"cannot be null");
}
// NOTE: as a first-pass implementation this simply instructs the
// caller to try again if retry is requested, but other strategies
// (like the number of times re-tried) might be considered later
if ((result instanceof ExceptionRetryStatus) &&
(((ExceptionRetryStatus) result).shouldRetry())) {
// Print a WARNING message if a task's retry count is a
// multiple of a configurable threshold
if (task.getTryCount() % retryWarningThreshold == 0) {
logger.logThrow(Level.WARNING,
task.getLastFailure(),
"Task has been retried {0} times: {1}",
task.getTryCount(), task);
}
// NOTE: this is a very simple initial policy that always causes
// tasks to re-try "in place"
return SchedulerRetryAction.RETRY_NOW;
} else {
// we're not re-trying the task, so specify reason for dropping it
if (logger.isLoggable(Level.FINE)) {
if (task.isRecurring()) {
logger.log(Level.FINE,
"skipping a recurrence of a task because it " +
"failed with a non-retryable exception: {0}",
task);
} else {
logger.log(Level.FINE,
"dropping a task because it failed with a " +
"non-retryable exception: {0}", task);
}
}
return SchedulerRetryAction.DROP;
}
}
}