java - Exception while creating index - Spring Data MongoDB -
i'm using spring-data spring-data mongodb map entity class using @compoundindexes annotation in i'm specifying indexes both names , definitions. in production environment, decided needed change of attributes of index based on actual data. every time application starts up, fails load because failure create index matching specification in annotation results , exception thrown during initialization process (as seen below).
is there anyway of configuring spring data , mongodb these exceptions logged not fail start of container?
exception while creating index ! com.mongodb.mongocommandexception: command failed error 86: 'trying create index same name event_source_link_type_at_id_idx different key spec **** vs existing spec *****' on server 127.0.0.1:27017. full response { "ok" : 0.0, "errmsg" : "trying create index same name event_source_link_type_at_id_idx different key spec **** vs existing spec *****", "code" : 86 } ! @ com.mongodb.connection.protocolhelper.getcommandfailureexception(protocolhelper.java:115) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.connection.commandprotocol.execute(commandprotocol.java:114) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.connection.defaultserver$defaultserverprotocolexecutor.execute(defaultserver.java:159) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.connection.defaultserverconnection.executeprotocol(defaultserverconnection.java:286) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.connection.defaultserverconnection.command(defaultserverconnection.java:173) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.commandoperationhelper.executewrappedcommandprotocol(commandoperationhelper.java:215) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.commandoperationhelper.executewrappedcommandprotocol(commandoperationhelper.java:198) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.commandoperationhelper.executewrappedcommandprotocol(commandoperationhelper.java:170) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.createindexesoperation$1.call(createindexesoperation.java:116) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.createindexesoperation$1.call(createindexesoperation.java:111) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.operationhelper.withconnectionsource(operationhelper.java:230) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.operationhelper.withconnection(operationhelper.java:221) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.createindexesoperation.execute(createindexesoperation.java:111) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.operation.createindexesoperation.execute(createindexesoperation.java:66) ~[mongodb-driver-core-3.2.2.jar:na] ! @ com.mongodb.mongo.execute(mongo.java:781) ~[mongodb-driver-3.2.2.jar:na] ! @ com.mongodb.mongo$2.execute(mongo.java:764) ~[mongodb-driver-3.2.2.jar:na] ! @ com.mongodb.dbcollection.createindex(dbcollection.java:1541) ~[mongodb-driver-3.2.2.jar:na] ! @ org.springframework.data.mongodb.core.index.mongopersistententityindexcreator.createindex(mongopersistententityindexcreator.java:142) [spring-data-mongodb-1.8.4.release.jar:na]
turns out isn't easy thought can done few classes.
first need override class creates indexes , overwrite method creates indexes, trapping exceptions match , logging them.
unfortunately package protected need create class in same package class we're extending.
package org.springframework.data.mongodb.core.index; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.data.mongodb.mongodbfactory; import org.springframework.data.mongodb.core.mapping.mongomappingcontext; public class exceptionignoringindexcreator extends mongopersistententityindexcreator { //assuming slf4j logger otherwise, put logger here private static final logger log = loggerfactory.getlogger(exceptionignoringindexcreator.class); public exceptionignoringindexcreator(mongomappingcontext mappingcontext, mongodbfactory mongodbfactory) { super(mappingcontext, mongodbfactory); } @override void createindex(mongopersistententityindexresolver.indexdefinitionholder indexdefinition) { try { super.createindex(indexdefinition); } catch (final runtimeexception exp) { final runtimeexception trans = translate(exp); if (trans != null) { throw trans; } else { log.warn("exception while creating index", exp); } } } protected runtimeexception translate(final runtimeexception exp) { if (exp == null || exp.getmessage().contains("cannot create index")) { return null; } return exp; } }
the index creation triggered event published mongomappingcontext using applicationeventpublisherinterface. need class can lazily set applicationeventpublisher delegate 2 methods of interface delegate calls to.
public class delegatingpublisher implements applicationeventpublisher { private applicationeventpublisher delegate; @override public void publishevent(applicationevent event) { delegate.publishevent(event); } @override public void publishevent(object event) { delegate.publishevent(event); } public void setdelegate(applicationeventpublisher delegate) { this.delegate = delegate; } }
normally configure spring data mongodb using class extends abstractmongoconfig , overrides "mongo()" method.
the component responsible publishing message initializes indexes 1 returned "mongomappingcontext()" you'll need override method , extend default mongomappingcontext overriding method sets event publisher , passing our new delegate publisher in place.
@configuration @enablemongorepositories("com.my.company") public class mymongoconfig extends abstractmongoconfiguration { ... @override @bean public mongomappingcontext mongomappingcontext() throws classnotfoundexception { final delegatingpublisher dep = new delegatingpublisher(); final mongomappingcontext mappingcontext = new mongomappingcontext() { @override public void setapplicationeventpublisher(applicationeventpublisher applicationeventpublisher) { super.setapplicationeventpublisher(dep); } }; mappingcontext.setinitialentityset(getinitialentityset()); mappingcontext.setsimpletypeholder(customconversions().getsimpletypeholder()); mappingcontext.setfieldnamingstrategy(fieldnamingstrategy()); try { final mongopersistententityindexcreator indexcreator = new exceptionignoringindexcreator(mappingcontext, mongodbfactory()); dep.setdelegate(new mongomappingeventpublisher(indexcreator)); return mappingcontext; } catch (exception exp) { throw new runtimeexception(exp); } } ... }
if use xml based configuration, you'll need 1 more class , specified configuration
public class eventdelegatingmongomappingcontext extends mongomappingcontext { private applicationeventpublisher publisher; public eventdelegatingmongomappingcontext(applicationeventpublisher publisher) { this.publisher = publisher; } @override public void setapplicationeventpublisher(applicationeventpublisher applicationeventpublisher) { super.setapplicationeventpublisher(publisher); } }
<mongo:db-factory id="mongodbfactory" host="localhost" port="27017" dbname="database" username="mycompany" password="secret"/> <bean id="delegatingpublisher" class="com.my.company.delegatingpublisher"> <property name="delegate" ref="mappingeventpublisher" /> </bean> <!-- must named 'mongomappingcontext' recognized --> <bean id="mongomappingcontext" class="com.my.company.eventdelegatingmongomappingcontext"> <constructor-arg> <bean ref="delegatingpublisher" /> </constructor-arg> </bean> <bean id="mongoindexcreator" class="org.springframework.data.mongodb.core.index.exceptionignoringindexcreator"> <constructor-arg> <bean ref="mongomappingcontext"/> </constructor-arg> <constructor-arg> <bean ref="mongodbfactory"/> </constructor-arg> </bean> <bean id="mappingeventpublisher" class="org.springframework.data.mongodb.core.index.mongomappingeventpublisher"> <constructor-arg> <bean ref="mongoindexcreator"/> </constructor-arg> </bean>
Comments
Post a Comment