001/*
002 * (C) Copyright 2006-2017 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.nuxeo.ecm.core.redis.retry;
017
018import org.apache.commons.logging.Log;
019import org.apache.commons.logging.LogFactory;
020
021public class Retry {
022
023    private static final Log log = LogFactory.getLog(Retry.class);
024
025    public interface Block<T> {
026        T retry() throws FailException, ContinueException;
027    }
028
029    public interface Policy {
030        boolean allow();
031
032        void pause();
033    }
034
035    public static class ContinueException extends Exception {
036
037        private static final long serialVersionUID = 1L;
038
039        public ContinueException(Throwable cause) {
040            super(cause);
041        }
042
043    }
044
045    public static class FailException extends Exception {
046
047        public FailException(String message) {
048            super(message);
049        }
050
051        public FailException(Throwable cause) {
052            super(cause);
053        }
054
055        private static final long serialVersionUID = 1L;
056
057    }
058
059    public <T> T retry(Block<T> block, Policy policy) throws FailException {
060        FailException causes = new FailException(
061                "Cannot execute block, retry policy failed, check suppressed exception for more infos");
062        while (policy.allow()) {
063            try {
064                return block.retry();
065            } catch (ContinueException error) {
066                if (log.isDebugEnabled()) {
067                    log.debug("An error occurred during redis script execution with policy=" + policy, error);
068                }
069                causes.addSuppressed(error.getCause());
070            } catch (FailException error) {
071                if (log.isDebugEnabled()) {
072                    log.debug("An error occurred during redis script execution with policy=" + policy, error);
073                }
074                causes.addSuppressed(error.getCause());
075                throw causes;
076            }
077            policy.pause();
078        }
079        throw causes;
080    }
081
082}