Alexander Wels has uploaded a new change for review. Change subject: userportal,webadmin: implement retry in Frontend ......................................................................
userportal,webadmin: implement retry in Frontend - Implemented retry mechanism in Frontend in case of failures. Change-Id: I68461d76cbbfa2f1c218f23023ce0e044ba9387e Signed-off-by: Alexander Wels <aw...@redhat.com> --- M frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java A frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/RetryManager.java M frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java 3 files changed, 253 insertions(+), 55 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/83/14583/1 diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java index 3da0e27..9f36783 100644 --- a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java +++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java @@ -19,6 +19,7 @@ import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.common.users.VdcUser; +import org.ovirt.engine.ui.frontend.RetryManager.RetryCallback; import org.ovirt.engine.ui.frontend.gwtservices.GenericApiGWTServiceAsync; import org.ovirt.engine.ui.uicompat.ConstantsManager; import org.ovirt.engine.ui.uicompat.Event; @@ -205,24 +206,37 @@ dumpQueryDetails(queryType, parameters); logger.finer("Frontend: Invoking async runQuery."); //$NON-NLS-1$ raiseQueryStartedEvent(queryType, callback.getContext()); + final RetryManager retryManager = new RetryManager(); final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); service.RunQuery(queryType, parameters, new AsyncCallback<VdcQueryReturnValue>() { @Override public void onFailure(final Throwable caught) { - try { - if (ignoreFailure(caught)) { - return; - } - logger.log(Level.SEVERE, "Failed to execute RunQuery: " + caught, caught); //$NON-NLS-1$ - getEventsHandler().runQueryFailed(null); - failureEventHandler(caught); - if (callback.isHandleFailure()) { - callback.asyncCallback.onSuccess(callback.getModel(), null); - } - raiseQueryCompleteEvent(queryType, callback.getContext()); - } finally { - if (isHandleSequentialQueries) { - handleSequentialQueries(queryWrapper.getKey()); + if (retryManager.canRetry()) { + final AsyncCallback<VdcQueryReturnValue> callback = this; + retryManager.retry(new RetryCallback() { + + @Override + public void executeRetry() { + service.RunQuery(queryType, parameters, callback); + } + }); + retryManager.incrementRetry(); + } else { + try { + if (ignoreFailure(caught)) { + return; + } + logger.log(Level.SEVERE, "Failed to execute RunQuery: " + caught, caught); //$NON-NLS-1$ + getEventsHandler().runQueryFailed(null); + failureEventHandler(caught); + if (callback.isHandleFailure()) { + callback.asyncCallback.onSuccess(callback.getModel(), null); + } + raiseQueryCompleteEvent(queryType, callback.getContext()); + } finally { + if (isHandleSequentialQueries) { + handleSequentialQueries(queryWrapper.getKey()); + } } } } @@ -288,19 +302,31 @@ initQueryParamsFilter(parameters); dumpQueryDetails(queryType, parameters); logger.finer("Frontend: Invoking async runQuery."); //$NON-NLS-1$ - - GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final RetryManager retryManager = new RetryManager(); + final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); service.RunPublicQuery(queryType, parameters, new AsyncCallback<VdcQueryReturnValue>() { @Override public void onFailure(final Throwable caught) { if (ignoreFailure(caught)) { return; } - logger.log(Level.SEVERE, "Failed to execute RunQuery: " + caught, caught); //$NON-NLS-1$ - getEventsHandler().runQueryFailed(null); - failureEventHandler(caught); - if (callback.isHandleFailure()) { - callback.asyncCallback.onSuccess(callback.getModel(), null); + if (retryManager.canRetry()) { + final AsyncCallback<VdcQueryReturnValue> callback = this; + retryManager.retry(new RetryCallback() { + + @Override + public void executeRetry() { + service.RunPublicQuery(queryType, parameters, callback); + } + }); + retryManager.incrementRetry(); + } else { + logger.log(Level.SEVERE, "Failed to execute RunQuery: " + caught, caught); //$NON-NLS-1$ + getEventsHandler().runQueryFailed(null); + failureEventHandler(caught); + if (callback.isHandleFailure()) { + callback.asyncCallback.onSuccess(callback.getModel(), null); + } } } @@ -356,20 +382,33 @@ initQueryParamsFilter(parameters); } - GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final RetryManager retryManager = new RetryManager(); service.RunMultipleQueries(queryTypeList, queryParamsList, new AsyncCallback<ArrayList<VdcQueryReturnValue>>() { @Override public void onFailure(final Throwable caught) { if (ignoreFailure(caught)) { return; } - logger.log(Level.SEVERE, "Failed to execute RunPublicQuery: " + caught, caught); //$NON-NLS-1$ - FrontendMultipleQueryAsyncResult f = - new FrontendMultipleQueryAsyncResult(queryTypeList, queryParamsList, null); - failureEventHandler(caught); - callback.executed(f); + if (retryManager.canRetry()) { + final AsyncCallback<ArrayList<VdcQueryReturnValue>> callback = this; + retryManager.retry(new RetryCallback() { - raiseQueryCompleteEvent(queryTypeList, context); + @Override + public void executeRetry() { + service.RunMultipleQueries(queryTypeList, queryParamsList, callback); + } + }); + retryManager.incrementRetry(); + } else { + logger.log(Level.SEVERE, "Failed to execute RunPublicQuery: " + caught, caught); //$NON-NLS-1$ + FrontendMultipleQueryAsyncResult f = + new FrontendMultipleQueryAsyncResult(queryTypeList, queryParamsList, null); + failureEventHandler(caught); + callback.executed(f); + + raiseQueryCompleteEvent(queryTypeList, context); + } } @Override @@ -454,7 +493,7 @@ } /** - * Run an action of the specified action type using the passed in parameters, also pass in a state object + * Run an action of the specified action type using the passed in parameters, also pass in a state object. * @param actionType The action type of the action to perform. * @param parameters The parameters of the action. * @param callback The callback to call when the action is completed. @@ -481,17 +520,30 @@ logger.finer("Invoking async runAction."); //$NON-NLS-1$ dumpActionDetails(actionType, parameters); - GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final RetryManager retryManager = new RetryManager(); service.RunAction(actionType, parameters, new AsyncCallback<VdcReturnValueBase>() { @Override public void onFailure(final Throwable caught) { if (ignoreFailure(caught)) { return; } - logger.log(Level.SEVERE, "Failed to execute RunAction: " + caught, caught); //$NON-NLS-1$ - failureEventHandler(caught); - FrontendActionAsyncResult f = new FrontendActionAsyncResult(actionType, parameters, null, state); - callback.executed(f); + if (retryManager.canRetry()) { + final AsyncCallback<VdcReturnValueBase> callback = this; + retryManager.retry(new RetryCallback() { + + @Override + public void executeRetry() { + service.RunAction(actionType, parameters, callback); + } + }); + retryManager.incrementRetry(); + } else { + logger.log(Level.SEVERE, "Failed to execute RunAction: " + caught, caught); //$NON-NLS-1$ + failureEventHandler(caught); + FrontendActionAsyncResult f = new FrontendActionAsyncResult(actionType, parameters, null, state); + callback.executed(f); + } } @Override @@ -521,8 +573,8 @@ final boolean isRunOnlyIfAllCanDoPass, final IFrontendMultipleActionAsyncCallback callback, final Object state) { - GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); - + final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final RetryManager retryManager = new RetryManager(); service.RunMultipleActions(actionType, parameters, isRunOnlyIfAllCanDoPass, @@ -532,12 +584,25 @@ if (ignoreFailure(caught)) { return; } - logger.log(Level.SEVERE, "Failed to execute RunAction: " + caught, caught); //$NON-NLS-1$ - failureEventHandler(caught); + if (retryManager.canRetry()) { + final AsyncCallback<ArrayList<VdcReturnValueBase>> callback = this; + retryManager.retry(new RetryCallback() { - if (callback != null) { - callback.executed(new FrontendMultipleActionAsyncResult(actionType, parameters, null, - state)); + @Override + public void executeRetry() { + service.RunMultipleActions(actionType, parameters, isRunOnlyIfAllCanDoPass, + callback); + } + }); + retryManager.incrementRetry(); + } else { + logger.log(Level.SEVERE, "Failed to execute RunAction: " + caught, caught); //$NON-NLS-1$ + failureEventHandler(caught); + + if (callback != null) { + callback.executed(new FrontendMultipleActionAsyncResult(actionType, parameters, null, + state)); + } } } @@ -614,7 +679,8 @@ final AsyncQuery callback) { logger.finer("Frontend: Invoking async Login."); //$NON-NLS-1$ - GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final RetryManager retryManager = new RetryManager(); service.Login(userName, password, domain, new AsyncCallback<VdcReturnValueBase>() { @Override public void onSuccess(final VdcReturnValueBase result) { @@ -634,21 +700,39 @@ if (ignoreFailure(caught)) { return; } - logger.log(Level.SEVERE, "Failed to execute RunQuery: " + caught, caught); //$NON-NLS-1$ - getEventsHandler().runQueryFailed(null); - failureEventHandler(caught); - if (callback.isHandleFailure()) { - setLoggedInUser(null); - callback.asyncCallback.onSuccess(callback.getModel(), null); + if (retryManager.canRetry()) { + final AsyncCallback<VdcReturnValueBase> callback = this; + retryManager.retry(new RetryCallback() { + + @Override + public void executeRetry() { + service.Login(userName, password, domain, callback); + } + }); + retryManager.incrementRetry(); + } else { + logger.log(Level.SEVERE, "Failed to execute RunQuery: " + caught, caught); //$NON-NLS-1$ + getEventsHandler().runQueryFailed(null); + failureEventHandler(caught); + if (callback.isHandleFailure()) { + setLoggedInUser(null); + callback.asyncCallback.onSuccess(callback.getModel(), null); + } } } }); } - public static void LogoffAsync(VdcUser vdcUser, final AsyncQuery callback) { + /** + * Log off the passed in user asynchronously. + * @param vdcUser The user object to log off. + * @param callback The callback to call when finished. + */ + public static void LogoffAsync(final VdcUser vdcUser, final AsyncQuery callback) { logger.finer("Frontend: Invoking async Logoff."); //$NON-NLS-1$ - GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); + final RetryManager retryManager = new RetryManager(); service.logOff(vdcUser, new AsyncCallback<VdcReturnValueBase>() { @Override public void onSuccess(final VdcReturnValueBase result) { @@ -664,10 +748,22 @@ if (ignoreFailure(caught)) { return; } - logger.log(Level.SEVERE, "Failed to execute Logoff: " + caught, caught); //$NON-NLS-1$ - getEventsHandler().runQueryFailed(null); - failureEventHandler(caught); - callback.asyncCallback.onSuccess(callback.getModel(), null); + if (retryManager.canRetry()) { + final AsyncCallback<VdcReturnValueBase> callback = this; + retryManager.retry(new RetryCallback() { + + @Override + public void executeRetry() { + service.logOff(vdcUser, callback); + } + }); + retryManager.incrementRetry(); + } else { + logger.log(Level.SEVERE, "Failed to execute Logoff: " + caught, caught); //$NON-NLS-1$ + getEventsHandler().runQueryFailed(null); + failureEventHandler(caught); + callback.asyncCallback.onSuccess(callback.getModel(), null); + } } }); } @@ -688,7 +784,7 @@ logger.finer("Determining whether user is logged in..."); //$NON-NLS-1$ final GenericApiGWTServiceAsync service = GenericApiGWTServiceAsync.Util.getInstance(); - + final RetryManager retryManager = new RetryManager(); service.getLoggedInUser(new AsyncCallback<VdcUser>() { @Override public void onFailure(final Throwable caught) { diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/RetryManager.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/RetryManager.java new file mode 100644 index 0000000..bf348f2 --- /dev/null +++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/RetryManager.java @@ -0,0 +1,101 @@ +package org.ovirt.engine.ui.frontend; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.gwt.user.client.Random; +import com.google.gwt.user.client.Timer; + +/** + * This class manages the retry counter for the {@code Frontend}. + */ +public class RetryManager { + /** + * Implement this interface if you want the retry manager to make a callback. + */ + public interface RetryCallback { + /** + * The method to execute when retrying. + */ + void executeRetry(); + } + + /** + * The logger. + */ + private static final Logger log = Logger.getLogger(RetryManager.class.getName()); + + /** + * Maximum number of retries. + */ + private static final int MAX_RETRY_COUNT = 5; + + /** + * The starting sleep time in seconds. + */ + private static final int START_SLEEP = 1; // Sleep 1 seconds. + + /** + * Number of milliseconds in a second. + */ + private static final int MILLISECONDS = 1000; // Number of milliseconds in a second. + + /** + * The max random time to add to wait interval. + */ + private static final int MAX_RANDOM_SLEEP = 250; // Add a maximum 250 milliseconds. + + /** + * The retry count. + */ + private int counter = 0; + + /** + * Increment the retry counter. + */ + public void incrementRetry() { + counter++; + } + + /** + * Check if we can still retry whatever we are trying. + * @return {@code true} if the counter is less than max, {@code false} otherwise + */ + public boolean canRetry() { + log.log(Level.FINEST, "canRetry called, can we retry? " + (counter < MAX_RETRY_COUNT)); //$NON-NLS-1$ + return counter < MAX_RETRY_COUNT; + } + + /** + * execute the retry after a calculated number of seconds. + * @param retryCallback The callback to use to retry. + */ + public void retry(final RetryCallback retryCallback) { + Timer retryTimer = new Timer() { + public void run() { + if (retryCallback != null) { + retryCallback.executeRetry(); + } else { + log.log(Level.WARNING, "retry called without callback, not retrying anything"); //$NON-NLS-1$ + } + } + }; + retryTimer.schedule(calculateSleep() * MILLISECONDS + Random.nextInt(MAX_RANDOM_SLEEP)); + } + + /** + * Calculate the retry sleep time in seconds. + * @return The number of seconds to wait before retrying. + */ + private int calculateSleep() { + int sleep = 1; + for (int i = 1; i <= counter; i++) { + if (i == 1) { + sleep = START_SLEEP; + } + sleep = sleep * 2; // Double sleep each retry. + } + log.log(Level.INFO, "Sleeping for: " + sleep + " seconds"); //$NON-NLS-1$ //$NON-NLS-2$ + return sleep; + } +} diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java index f65a690..c858a72 100644 --- a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java +++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java @@ -30,6 +30,7 @@ static Random r = new Random(); boolean noBackend = false; + int errorCount = 0; private static final Logger log = Logger.getLogger(GenericApiGWTServiceImpl.class); -- To view, visit http://gerrit.ovirt.org/14583 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I68461d76cbbfa2f1c218f23023ce0e044ba9387e Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Alexander Wels <aw...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches