From c13926708f5fe5445c50217e16b6a8dc867791b7 Mon Sep 17 00:00:00 2001 From: Paul Ferraro Date: Fri, 7 Apr 2017 11:27:48 -0400 Subject: [PATCH] WFLY-8540 Former singleton provider node leaving cluster after re-election causes another re-election --- clustering/singleton/extension/pom.xml | 15 ++++++ .../singleton/ElectionPolicyBuilder.java | 3 +- .../clustering/singleton/SingletonLogger.java | 46 +++++++++++++++++++ .../singleton/SingletonPolicyBuilder.java | 5 ++ ...ingletonDeploymentDependencyProcessor.java | 12 ++--- .../SingletonDeploymentProcessor.java | 31 ++++++++++--- ...ingletonSubDeploymentUnitPhaseBuilder.java | 37 --------------- 7 files changed, 98 insertions(+), 51 deletions(-) create mode 100644 clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonLogger.java delete mode 100644 clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonSubDeploymentUnitPhaseBuilder.java diff --git a/clustering/singleton/extension/pom.xml b/clustering/singleton/extension/pom.xml index 4e6340e47f84..36e30b40c6ab 100644 --- a/clustering/singleton/extension/pom.xml +++ b/clustering/singleton/extension/pom.xml @@ -59,6 +59,21 @@ metainf-services provided + + org.jboss.logging + jboss-logging + provided + + + org.jboss.logging + jboss-logging-annotations + provided + + + org.jboss.logging + jboss-logging-processor + provided + org.wildfly wildfly-clustering-common diff --git a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/ElectionPolicyBuilder.java b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/ElectionPolicyBuilder.java index 5f1fb79a1aea..1d72b6c52f35 100644 --- a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/ElectionPolicyBuilder.java +++ b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/ElectionPolicyBuilder.java @@ -36,7 +36,6 @@ import org.jboss.as.network.OutboundSocketBinding; import org.jboss.dmr.ModelNode; import org.jboss.msc.service.ServiceBuilder; -import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceTarget; import org.jboss.msc.service.ValueService; import org.jboss.msc.value.Value; @@ -65,7 +64,7 @@ protected ElectionPolicyBuilder(PathAddress policyAddress) { @Override public ServiceBuilder build(ServiceTarget target) { Value value = () -> this.preferences.isEmpty() ? this.getValue() : new PreferredSingletonElectionPolicy(this.getValue(), this.preferences); - ServiceBuilder builder = target.addService(this.getServiceName(), new ValueService<>(value)).setInitialMode(ServiceController.Mode.ON_DEMAND); + ServiceBuilder builder = target.addService(this.getServiceName(), new ValueService<>(value)); this.dependencies.forEach(dependency -> dependency.register(builder)); return builder; } diff --git a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonLogger.java b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonLogger.java new file mode 100644 index 000000000000..37a644789a34 --- /dev/null +++ b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonLogger.java @@ -0,0 +1,46 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2017, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.extension.clustering.singleton; + +import static org.jboss.logging.Logger.Level.INFO; + +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; +import org.jboss.logging.annotations.MessageLogger; +import org.wildfly.clustering.singleton.SingletonPolicy; + +/** + * @author Paul Ferraro + */ +@MessageLogger(projectCode = "WFLYCLSNG", length = 4) +public interface SingletonLogger extends BasicLogger { + String ROOT_LOGGER_CATEGORY = "org.wildfly.extension.clustering.singleton"; + + SingletonLogger ROOT_LOGGER = Logger.getMessageLogger(SingletonLogger.class, ROOT_LOGGER_CATEGORY); + + @LogMessage(level = INFO) + @Message(id = 1, value = "Singleton deployment detected. Deployment will reset using %s policy.") + void singletonDeploymentDetected(SingletonPolicy policy); +} diff --git a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonPolicyBuilder.java b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonPolicyBuilder.java index 95e9b71a649c..f9c42e547607 100644 --- a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonPolicyBuilder.java +++ b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/SingletonPolicyBuilder.java @@ -102,4 +102,9 @@ public Builder createSingletonServiceBuilder(ServiceName name, Service .requireQuorum(this.quorum) ; } + + @Override + public String toString() { + return this.address.getLastElement().getValue(); + } } diff --git a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentDependencyProcessor.java b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentDependencyProcessor.java index 42a045dbd314..27e6ef8f6a72 100644 --- a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentDependencyProcessor.java +++ b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentDependencyProcessor.java @@ -42,12 +42,12 @@ public class SingletonDeploymentDependencyProcessor implements DeploymentUnitPro @Override public void deploy(DeploymentPhaseContext context) throws DeploymentUnitProcessingException { DeploymentUnit unit = context.getDeploymentUnit(); - DeploymentUnit parent = unit.getParent(); - // If this is a sub-deployment, any configuration will be attached to the parent deployment unit - SingletonDeploymentConfiguration config = ((parent != null) ? parent : unit).getAttachment(CONFIGURATION_KEY); - if (config != null) { - CapabilityServiceSupport support = unit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); - context.addDependency(SingletonServiceNameFactory.SINGLETON_POLICY.getServiceName(support, config.getPolicy()), SingletonDeploymentProcessor.POLICY_KEY); + if (unit.getParent() == null) { + SingletonDeploymentConfiguration config = unit.getAttachment(CONFIGURATION_KEY); + if (config != null) { + CapabilityServiceSupport support = unit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); + context.addDependency(SingletonServiceNameFactory.SINGLETON_POLICY.getServiceName(support, config.getPolicy()), SingletonDeploymentProcessor.POLICY_KEY); + } } } diff --git a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentProcessor.java b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentProcessor.java index 7f28895e44df..100758b3f43f 100644 --- a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentProcessor.java +++ b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonDeploymentProcessor.java @@ -26,10 +26,13 @@ import org.jboss.as.server.deployment.Attachments; import org.jboss.as.server.deployment.DeploymentPhaseContext; import org.jboss.as.server.deployment.DeploymentUnit; -import org.jboss.as.server.deployment.DeploymentUnitPhaseBuilder; import org.jboss.as.server.deployment.DeploymentUnitProcessingException; import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.msc.service.AbstractServiceListener; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceController.Mode; import org.wildfly.clustering.singleton.SingletonPolicy; +import org.wildfly.extension.clustering.singleton.SingletonLogger; /** * DUP that attaches the singleton DeploymentUnitPhaseBuilder if a deployment policy is attached. @@ -41,11 +44,27 @@ public class SingletonDeploymentProcessor implements DeploymentUnitProcessor { @Override public void deploy(DeploymentPhaseContext context) throws DeploymentUnitProcessingException { - SingletonPolicy policy = context.getAttachment(POLICY_KEY); - if (policy != null) { - DeploymentUnit parent = context.getDeploymentUnit().getParent(); - DeploymentUnitPhaseBuilder builder = (parent == null) ? new SingletonDeploymentUnitPhaseBuilder(policy) : new SingletonSubDeploymentUnitPhaseBuilder(parent, context.getPhase().next()); - context.putAttachment(Attachments.DEPLOYMENT_UNIT_PHASE_BUILDER, builder); + DeploymentUnit unit = context.getDeploymentUnit(); + if (unit.getParent() == null) { + SingletonPolicy policy = context.getAttachment(POLICY_KEY); + if (policy != null) { + // Ideally, we would just install the next phase using the singleton policy, however deployment unit phases do not currently support restarts + // Restart the deployment using the attached phase builder, but only if a builder was not already attached + if (unit.putAttachment(Attachments.DEPLOYMENT_UNIT_PHASE_BUILDER, new SingletonDeploymentUnitPhaseBuilder(policy)) == null) { + SingletonLogger.ROOT_LOGGER.singletonDeploymentDetected(policy); + ServiceController controller = context.getServiceRegistry().getRequiredService(unit.getServiceName()); + controller.addListener(new AbstractServiceListener() { + @Override + public void transition(final ServiceController controller, final ServiceController.Transition transition) { + if(transition.getAfter().equals(ServiceController.Substate.DOWN)) { + controller.setMode(Mode.ACTIVE); + controller.removeListener(this); + } + } + }); + controller.setMode(Mode.NEVER); + } + } } } diff --git a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonSubDeploymentUnitPhaseBuilder.java b/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonSubDeploymentUnitPhaseBuilder.java deleted file mode 100644 index 4570461d7809..000000000000 --- a/clustering/singleton/extension/src/main/java/org/wildfly/extension/clustering/singleton/deployment/SingletonSubDeploymentUnitPhaseBuilder.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.wildfly.extension.clustering.singleton.deployment; - -import org.jboss.as.server.deployment.DeploymentUnit; -import org.jboss.as.server.deployment.DeploymentUnitPhaseBuilder; -import org.jboss.as.server.deployment.DeploymentUtils; -import org.jboss.as.server.deployment.Phase; -import org.jboss.msc.service.Service; -import org.jboss.msc.service.ServiceBuilder; -import org.jboss.msc.service.ServiceController; -import org.jboss.msc.service.ServiceName; -import org.jboss.msc.service.ServiceTarget; -import org.jboss.msc.service.ValueService; - -/** - * Builds a service for a sub-deployment for the next phase in the deployment chain, if configured. - * @author Paul Ferraro - */ -public class SingletonSubDeploymentUnitPhaseBuilder implements DeploymentUnitPhaseBuilder { - private final DeploymentUnit parent; - private final Phase phase; - - SingletonSubDeploymentUnitPhaseBuilder(DeploymentUnit parent, Phase phase) { - this.parent = parent; - this.phase = phase; - } - - @Override - public ServiceBuilder build(ServiceTarget target, ServiceName name, Service service) { - // Install the actual phase service under some other name, and have it start automatically when the parent deployment's singleton service starts - target.addService(name.append("service"), service) - .addDependency(DeploymentUtils.getDeploymentUnitPhaseServiceName(this.parent, this.phase).append("primary")) - .setInitialMode(ServiceController.Mode.PASSIVE) - .install(); - // Return a dummy service builder - return target.addService(name, new ValueService<>(service)); - } -} \ No newline at end of file