All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.peterphi.std.guice.common.retry.module.RetryMethodInterceptor Maven / Gradle / Ivy

package com.peterphi.std.guice.common.retry.module;

import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.peterphi.std.guice.common.metrics.GuiceMetricNames;
import com.peterphi.std.guice.common.retry.annotation.Retry;
import com.peterphi.std.threading.Timeout;
import com.peterphi.std.guice.common.retry.retry.RetryManager;
import com.peterphi.std.guice.common.retry.retry.backoff.ExponentialBackoff;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;

import java.util.Arrays;

final class RetryMethodInterceptor implements MethodInterceptor
{
	private static final Logger log = Logger.getLogger(RetryMethodInterceptor.class);

	private final Timer calls;
	private final Timer attempts;
	private final Meter attemptFailures;
	private final Meter totalFailures;


	public RetryMethodInterceptor(MetricRegistry registry)
	{
		this.calls = registry.timer(GuiceMetricNames.RETRY_CALLS);
		this.attempts = registry.timer(GuiceMetricNames.RETRY_ATTEMPTS);

		this.attemptFailures = registry.meter(GuiceMetricNames.RETRY_ATTEMPT_FAILURES);
		this.totalFailures = registry.meter(GuiceMetricNames.RETRY_TOTAL_FAILURES);
	}


	@Override
	public Object invoke(final MethodInvocation invocation) throws Throwable
	{
		Timer.Context timer = this.calls.time();

		try
		{
			final Retry options = invocation.getMethod().getAnnotation(Retry.class);
			final RetryManager mgr = buildRetryManager(options);

			if (log.isTraceEnabled())
				log.trace("Attempting retryable invoke of " +
				          invocation.getMethod().toGenericString() +
				          " on " + invocation.getThis() + " with " +
				          Arrays.asList(invocation.getArguments()));

			return mgr.run(new InvocationRetryable(invocation, options.on(), options.exceptOn(), options.exceptOnCore()));
		}
		catch (Throwable t)
		{
			totalFailures.mark();

			if (log.isTraceEnabled())
				log.trace("Retrying invoke of " +
				          invocation.getMethod().toGenericString() +
				          " on " + invocation.getThis() + " with " +
				          Arrays.asList(invocation.getArguments()) + " failed.", t);

			throw t;
		}
		finally
		{
			timer.stop();
		}
	}


	private RetryManager buildRetryManager(Retry options)
	{
		final Timeout initial = new Timeout(options.backoffTime(), options.backoffUnit());

		ExponentialBackoff backoff = new ExponentialBackoff(initial, options.backoffExponent());

		return new RetryManager(backoff, options.maxAttempts(), attempts, attemptFailures);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy