Move LeaderInitiators to later phase

There is a race condition when Zookeeper `LeaderInitiator` may start
earlier than `CuratorFramework` it depends on.
This is because both of them are configured for the same default `phase` (`0`)

* Make `LeaderInitiator` and `LockRegistryLeaderInitiator` to be started
in the `Integer.MAX_VALUE - 1000` phase by default - as late as possible
* Make `CuratorFrameworkFactoryBean` to start in the `Integer.MIN_VALUE + 1000`
phase - as early as possible
* Alight lifecycle properties from the `LeaderInitiatorFactoryBean` with
defaults in the `LeaderInitiator`
* Simplify a `LeaderListenerParser` to rely on the `LeaderInitiatorFactoryBean`

**Cherry-pick to 5.0.x**
This commit is contained in:
Artem Bilan
2018-08-15 16:04:05 -04:00
committed by Gary Russell
parent ed07777b4e
commit 15eae700a3
5 changed files with 30 additions and 36 deletions

View File

@@ -151,7 +151,7 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
/**
* @see SmartLifecycle which is an extension of org.springframework.context.Phased
*/
private int phase;
private int phase = Integer.MAX_VALUE - 1000;
/**
* Flag that indicates whether the leadership election for this {@link #candidate} is

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2016 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,10 +27,11 @@ import org.springframework.context.SmartLifecycle;
import org.springframework.util.Assert;
/**
* A spring-friendly way to build a {@link CuratorFramework} and implementing {@link SmartLifecycle}.
* A Spring-friendly way to build a {@link CuratorFramework} and implementing {@link SmartLifecycle}.
*
* @author Gary Russell
* @author Artem Bilan
*
* @since 4.2
*/
public class CuratorFrameworkFactoryBean implements FactoryBean<CuratorFramework>, SmartLifecycle {
@@ -42,18 +43,18 @@ public class CuratorFrameworkFactoryBean implements FactoryBean<CuratorFramework
/**
* @see SmartLifecycle
*/
private volatile boolean autoStartup = true;
private boolean autoStartup = true;
/**
* @see SmartLifecycle
*/
private int phase = Integer.MIN_VALUE + 1000;
/**
* @see SmartLifecycle
*/
private volatile boolean running;
/**
* @see SmartLifecycle
*/
private volatile int phase;
/**
* Construct an instance using the supplied connection string and using a default
@@ -135,7 +136,7 @@ public class CuratorFrameworkFactoryBean implements FactoryBean<CuratorFramework
}
@Override
public CuratorFramework getObject() throws Exception {
public CuratorFramework getObject() {
return this.client;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2016 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@ import org.springframework.integration.zookeeper.leader.LeaderInitiator;
*
* @author Gary Russell
* @author Artem Bilan
*
* @since 4.2
*/
public class LeaderInitiatorFactoryBean
@@ -51,7 +52,7 @@ public class LeaderInitiatorFactoryBean
private boolean autoStartup = true;
private int phase;
private int phase = Integer.MAX_VALUE - 1000;
private ApplicationEventPublisher applicationEventPublisher;
@@ -136,11 +137,11 @@ public class LeaderInitiatorFactoryBean
if (this.leaderInitiator != null) {
return this.leaderInitiator.getPhase();
}
return 0;
return this.phase;
}
@Override
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
if (this.leaderInitiator == null) {
this.leaderInitiator = new LeaderInitiator(this.client, this.candidate, this.path);
this.leaderInitiator.setPhase(this.phase);
@@ -156,7 +157,7 @@ public class LeaderInitiatorFactoryBean
}
@Override
public synchronized LeaderInitiator getObject() throws Exception {
public synchronized LeaderInitiator getObject() {
return this.leaderInitiator;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2016 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,6 @@
package org.springframework.integration.zookeeper.config.xml;
import java.util.UUID;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -25,12 +23,12 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.leader.DefaultCandidate;
import org.springframework.integration.leader.event.DefaultLeaderEventPublisher;
import org.springframework.integration.zookeeper.leader.LeaderInitiator;
import org.springframework.integration.zookeeper.config.LeaderInitiatorFactoryBean;
/**
* @author Gary Russell
* @author Artem Bilan
*
* @since 4.2
*
*/
@@ -38,20 +36,14 @@ public class LeaderListenerParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder candidateBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultCandidate.class);
candidateBuilder.addConstructorArgValue(UUID.randomUUID().toString());
candidateBuilder.addConstructorArgValue(element.getAttribute("role"));
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(LeaderInitiatorFactoryBean.class)
.addPropertyReference("client", element.getAttribute("client"))
.addPropertyValue("role", element.getAttribute(IntegrationNamespaceUtils.ROLE))
.addPropertyValue("path", element.getAttribute("path"));
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(LeaderInitiator.class);
builder.addConstructorArgReference(element.getAttribute("client"));
builder.addConstructorArgValue(candidateBuilder.getBeanDefinition());
builder.addConstructorArgValue(element.getAttribute("path"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase");
BeanDefinitionBuilder publisherBuilder = BeanDefinitionBuilder
.genericBeanDefinition(DefaultLeaderEventPublisher.class);
builder.addPropertyValue("leaderEventPublisher", publisherBuilder.getBeanDefinition());
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.PHASE);
return builder.getBeanDefinition();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -88,7 +88,7 @@ public class LeaderInitiator implements SmartLifecycle {
/**
* @see SmartLifecycle which is an extension of org.springframework.context.Phased
*/
private volatile int phase;
private volatile int phase = Integer.MAX_VALUE - 1000;
/**
* Flag that indicates whether the leadership election for