不想在应用程序启动期间连接到cassandra联系点 - Spring Data Cassandra

时间:2018-04-23 19:02:52

标签: spring asynchronous cassandra nosql spring-data-cassandra

我的应用程序在两个不同的数据库(Oracle和Cassandra)上执行写操作(创建/更新/删除)。

即使cassandra集群出现故障,我也希望在Oracle中执行写入操作。

这就是为什么我在Cassandra中的所有写操作都是异步的,并且将在与Oracle不同的线程中执行。

在我的配置文件中,我使用@Lazy Annotation加载我的CassandraClusterFactoryBean。我还用try-catch包围它,所以当它无法连接到集群时,它不会抛出异常。

    @Bean
    @Lazy
    public CassandraClusterFactoryBean cluster() {
        CassandraClusterFactoryBean cluster = null;
        try{
         cluster = new CassandraClusterFactoryBean();
        cluster.setContactPoints(CASSANDRA_CONTACTPOINT);
        cluster.setPort(CASSANDRA_PORT);
        cluster.setUsername(CASSANDRA_USERNAME);
        cluster.setPassword(CASSANDRA_PASSWORD);
        }catch(Exception e){

            logger.info("Unable to contact Cassandra Cluster.");
        }
        return cluster;
    }

我已经创建了一个AsyncCompnent,它可以异步执行Cassandra的所有写操作。

@Component
public class AsyncComponent {

    @Autowired
    private OneWalletCassandraRepo oneWalletCassandraRepo;

    @Autowired
    private OneWalletProfileByCustUserIdRepo oneWalletProfileByCustUserIdRepo;

    @Autowired
    private OneWalletProfileByBillingCanRepo oneWalletProfileByBillingCanRepo;

    public static Logger logger = LogManager.getLogger(AsyncComponent.class);


    @Async
    public Future<Tonewalletprofile> saveCassandraAsync(Tonewalletprofile cassandraProfile) throws InterruptedException {

        logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());

        Tonewalletprofile savedCassandraProfile=oneWalletCassandraRepo.save(cassandraProfile);

        return new AsyncResult<>(savedCassandraProfile);
    }

    @Async
    public Future<Tonewalletprofile> findByPmtAccountRefIdAsync(int pmtAccountRefId) {

        logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());

        Tonewalletprofile foundCassandraProfile=oneWalletCassandraRepo.findByPmtAccountRefId(pmtAccountRefId);

        return new AsyncResult<>(foundCassandraProfile);
    }

    @Async
    public Future<List<TonewalletprofileByCustUserId>> findByCustUserIdAsync(String custUserId) {

        logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());

        List<TonewalletprofileByCustUserId> foundByCustUserId=oneWalletProfileByCustUserIdRepo.findByCustUserId(custUserId);

        return new AsyncResult<>(foundByCustUserId);
    }

    @Async
    public Future<List<TonewalletprofileByBillingCan>> findByBillingAcctNumAsync(String billingAcctNum) {

        logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());

        List<TonewalletprofileByBillingCan> foundByBillingAcctNum=oneWalletProfileByBillingCanRepo.findByBillingAcctNum(billingAcctNum);

        return new AsyncResult<>(foundByBillingAcctNum);
    }

    @Async
    public void deleteCassandraAsync(Tonewalletprofile cassandraProfile) {

        logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());

        oneWalletCassandraRepo.delete(cassandraProfile);
    }

}

然后,我使用@Lazy Annotation在我的Service类中自动连接此组件。

为了Sanity的缘故,我还用@Lazy自动装配了我的Threadpoolexceutor和AsyncExceptionHanlder

    @Override
    @Lazy
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }

    @Override
    @Lazy
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }

当我放下cassandra集群时,当我启动我的应用程序时,它仍然试图寻找接触点并且它失败了。 (点击展开)

enter image description here

我不确定为什么会这样。

基本上我想要的是即使集群发生故障,Oracle DB上的Write操作也应该顺利进行。

2 个答案:

答案 0 :(得分:2)

您可以这样做:

禁用spring数据cassandra自动配置:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;

@SpringBootApplication(exclude = {
    CassandraDataAutoConfiguration.class
})
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

使用@Lazy及其依赖项创建您自己的CassandraTemplate:

import com.datastax.driver.core.Cluster;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.cassandra.config.CassandraTemplateFactoryBean;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;

/**
 * @author fabiojose
 */
@Configuration
public class Config  {

    @Bean
    @Lazy
    public Cluster cassandra() {

        return 
        Cluster.builder()
            .addContactPoint("localhost")
            .withoutMetrics()
            .withPort(9042)
            .build();
    }

    @Bean
    @Lazy
    public CassandraMappingContext mappingContext() {
        return new CassandraMappingContext();
    }

    @Bean
    @Lazy
    public CassandraConverter converter() {
        return new MappingCassandraConverter(mappingContext());
    }

    @Bean
    @Lazy
    public CassandraTemplateFactoryBean cassandraTemplate(Cluster cassandra,
        CassandraConverter converter) {

        CassandraTemplateFactoryBean factory = new CassandraTemplateFactoryBean();

        factory.setConverter(converter);
        factory.setSession(cassandra.newSession());

        return factory;
    }
}

答案 1 :(得分:1)

Spring Data Cassandra组件在启动期间初始化的Session对象上运行。创建初始化的Session需要与Cassandra主机进行远程交互,因此如果无法访问主机,您会看到失败。

只要通过org.springframework.data.cassandra.SessionFactory请求Session,您就可以启动自己的Session并懒洋洋地初始化它。 CqlTemplateCassandraTemplate都接受SessionFactory作为构造函数args。