-
Notifications
You must be signed in to change notification settings - Fork 40.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for customized Cassandra keyspace creations #15821
Comments
Thanks for the suggestion. I don't know if that's the code you are using now but importing the auto-configurations the way you do is quite unusual (and probably unnecessary) . What is wrong with getting the |
Thanks for the quick response...
yes I know that's why i called it "ugly" myself. The import was necessary because CassandraDataAutoConfiguration is disabled due to the
Trying that failed for me because |
I don't see why it was. If you provide your own
Thanks that helps. |
You're right, my bad - there's no need for the import in prod code. I checked again and it was only a test that run in to a |
@philwebb would you like to share the reason why this was declined? |
👍 o.k. - thanks for clarifying and reopening. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
We'll look at offering first-class support for this in a future 2.x release. In the meantime, I think it can be achieved reasonably cleanly using a @Bean
public static BeanPostProcessor keyspaceCreator() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof Cluster) {
Cluster cluster = (Cluster) bean;
try (Session session = cluster.connect()) {
session.execute(CreateKeyspaceCqlGenerator.toCql(getSimpleKeyspaceCreation()));
}
}
return bean;
}
private CreateKeyspaceSpecification getSimpleKeyspaceCreation() {
return CreateKeyspaceSpecification.createKeyspace("foo").ifNotExists();
}
};
} @rreimann If you've already tried something like this and it didn't work, I'd be very interested to hear about the problems that you had. |
Hi, I would like to take this issue with a friend of mine (@manduinca) but I have been checking that there are many just pinging to @mp911de in case I am missing something |
I'm not convinced of creating a keyspace on startup is a use-case worth supporting. It compares to There is another point to consider which is the evolution of the Cassandra driver (version 4.x). In Cassandra driver 3.x and earlier, the driver makes a distinction between a With Cassandra driver 4, the setup changes to: CqlSession session = CqlSession.builder().build();
ResultSet rs = session.execute("select release_version from system.local"); There's no longer an intermediate Please also note that I'd suggest revisiting schema migration in the context of the Cassandra driver 4 migration. Check out DATACASS-187 for further reference. |
Thanks for the quick reply @mp911de !
Good point
Thanks for the reference |
@wilkinsona @snicoll With version 4 of the Cassandra driver the Cluster class goes away and instantiating the
The best solution I could find was to override the @Bean
public CqlSession cassandraSession(CqlSessionBuilder cqlSessionBuilder, CassandraProperties properties) {
String keyspaceName = properties.getKeyspaceName();
// keyspaceName must be null for the session creating the keyspace
try (CqlSession session = cqlSessionBuilder.withKeyspace((CqlIdentifier) null).build()) {
session.execute(CreateKeyspaceCqlGenerator.toCql(
CreateKeyspaceSpecification.createKeyspace(keyspaceName).ifNotExists()));
}
// restore keyspaceName before creating the session
return cqlSessionBuilder.withKeyspace(keyspaceName).build();
} Do you see a more elegant option? Would this be a good time to provide this functionality out of the box? When running Cassandra for integration tests or local development you typically get a barebones container and it's convenient to (optionally) have the ability to create the keyspace at startup. |
Another reason for adding keyspace creation is feature parity with the configuration from |
The Spring Data team advised against supporting this in the past. What's your take on this now please, @mp911de, now that Boot's using the 4.x driver? |
If other people have the same need, here is my final solution in the form of an auto-configuration that I've added to our company's starter. I've also introduced a property to make the functionality opt-in. /**
* create the configured keyspace before the first cqlSession is instantiated. This is guaranteed by running this
* autoconfiguration before the spring-boot one.
*/
@ConditionalOnClass(CqlSession.class)
@ConditionalOnProperty(name = "spring.data.cassandra.create-keyspace", havingValue = "true")
@AutoConfigureBefore(CassandraAutoConfiguration.class)
public class CassandraCreateKeyspaceAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(CassandraCreateKeyspaceAutoConfiguration.class);
public CassandraCreateKeyspaceAutoConfiguration(CqlSessionBuilder cqlSessionBuilder, CassandraProperties properties) {
// It's OK to mutate cqlSessionBuilder because it has prototype scope.
try (CqlSession session = cqlSessionBuilder.withKeyspace((CqlIdentifier) null).build()) {
logger.info("Creating keyspace {} ...", properties.getKeyspaceName());
session.execute(CreateKeyspaceCqlGenerator.toCql(
CreateKeyspaceSpecification.createKeyspace(properties.getKeyspaceName()).ifNotExists()));
}
}
} |
Keyspace creation is typically an operations task similar to SQL databases where the application connects to an existing database instead of creating one. Therefore, this feature is not a first-class citizen. Spring Data Cassandra's |
Having the support in spring data for creating keyspace is encouraging. However, I don't see support for a small property "ifNotExists" while creating keyspace. I am using spring data cassandra ver 3.3.1. Able to successfully create keyspace on first run. However on rerunning the app I get exception com.datastax.oss.driver.api.core.servererrors.AlreadyExistsException. I am aware that by overriding the behavior of Bean class I could get past this. But would like to know if a solution already exist or will it be provided in XML config. Thank You. |
I agree with @mp911de's comment, especially in the context of production systems or already running environments.
But Spring Boot has long provided great support for unit testing, which is where this feature is needed. The core issue is that the DataStax v4 driver requires that the keyspace be created ahead of time or it fails. Docker has become a core part of many companies workflows and with the ease at which we can automate, the expectations have changed as well, such that there is less tolerance for manual configuration - especially for CI environments. Most Cassandra containers come without any keyspace created, and not all of the automation tooling provide an easy way to inject it into the workflow: e.g. (1) start a container, (2) create a keyspace, then (3) run tests. I've tried @bcalmac's clever constructor-based auto-configuration, but haven't been able to get it to run before Spring Boot's I think Spring Boot has an opportunity to make unit tests against Cassandra containers much easier by auto-creating the keyspace if it's not already there - perhaps based on a property as @bcalmac suggested. |
I can't get the solution from @bcalmac working as well, and I solved it like this in my tests: @Configuration
class CassandraConfiguration {
@Bean
CqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder, CassandraProperties properties) {
// This creates the keyspace on startup
try (CqlSession session = cqlSessionBuilder.build()) {
session.execute(CreateKeyspaceCqlGenerator
.toCql(CreateKeyspaceSpecification.createKeyspace(properties.getKeyspaceName()).ifNotExists()));
}
return cqlSessionBuilder.build();
}
} They too use docker, and I agree with @pluttrell that triggering a key space creation via properties would have spared me the headache of finding out how to do this programmatically. This feature might not be needed in production arrangements, but would be a boon to integration testing. |
Using the
Cluster
bean fromCassandraAutoConfiguration
makes it quite difficult to provide a custom keyspace creation (e.g. viaCreateKeyspaceSpecification
).While
CassandraClusterFactoryBean#setKeyspaceCreations
provides support for custom keyspace creations I couldn't find anything similar when the cluster is created via the auto-configuration.Trying to find a workaround that doesn't duplicate existing auto-configuration code led to this ugly custom configuration...
It would be nice if the auto-configuration would provide support for keyspace creations.
The text was updated successfully, but these errors were encountered: