Add new isHealthy() methods to EntityCollectionManager and EntityIndex, and add new HealthCheckFilter that calls them so we can fail fast when ES or C* not available.
Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/b6a8bc62 Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/b6a8bc62 Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/b6a8bc62 Branch: refs/heads/two-dot-o Commit: b6a8bc6248dfaebec33d7842feace04a0dfaf5c6 Parents: 5570b9d Author: Dave Johnson <[email protected]> Authored: Fri Oct 31 11:31:32 2014 -0400 Committer: Dave Johnson <[email protected]> Committed: Fri Oct 31 11:31:32 2014 -0400 ---------------------------------------------------------------------- .../corepersistence/CpEntityManagerFactory.java | 20 ++++ .../HybridEntityManagerFactory.java | 10 ++ .../persistence/EntityManagerFactory.java | 4 + .../cassandra/EntityManagerFactoryImpl.java | 10 ++ .../collection/EntityCollectionManager.java | 10 +- .../impl/EntityCollectionManagerImpl.java | 107 ++++++++++++------- .../serialization/SerializationFig.java | 4 - .../collection/EntityCollectionManagerIT.java | 12 +++ .../usergrid/persistence/index/EntityIndex.java | 14 +-- .../index/impl/EsEntityIndexImpl.java | 76 ++++++++----- .../impl/EntityConnectionIndexImplTest.java | 22 +++- .../src/test/resources/logback-test.xml | 19 ++++ stack/loadtests/src/test/resources/logback.xml | 3 +- .../apache/usergrid/rest/SwaggerServlet.java | 5 +- .../rest/filters/HealthCheckFilter.java | 68 ++++++++++++ stack/rest/src/main/webapp/WEB-INF/web.xml | 10 ++ 16 files changed, 306 insertions(+), 88 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java index 6e6b461..cf9207a 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java @@ -50,6 +50,7 @@ import org.apache.usergrid.persistence.cassandra.CassandraService; import org.apache.usergrid.persistence.cassandra.CounterUtils; import org.apache.usergrid.persistence.cassandra.Setup; import org.apache.usergrid.persistence.collection.CollectionScope; +import org.apache.usergrid.persistence.collection.EntityCollectionManager; import org.apache.usergrid.persistence.collection.EntityCollectionManagerFactory; import org.apache.usergrid.persistence.collection.impl.CollectionScopeImpl; import org.apache.usergrid.persistence.core.scope.ApplicationScope; @@ -719,4 +720,23 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application public void rebuildCollectionIndex(UUID appId, String collection, ProgressObserver po ) { throw new UnsupportedOperationException( "Not supported yet." ); } + + @Override + public boolean verifyCollectionsModuleHealthy() { + + CollectionScope collScope = new CollectionScopeImpl( + getApplicationScope(SYSTEM_APP_ID).getApplication(), + getApplicationScope(SYSTEM_APP_ID).getApplication(), + CpNamingUtils.getCollectionScopeNameFromCollectionName( "appinfos" )); + + EntityCollectionManager ecm = managerCache.getEntityCollectionManager( collScope ); + return ecm.isHealthy(); + } + + @Override + public boolean verifyQueryIndexModuleHealthy() { + + EntityIndex ei = managerCache.getEntityIndex( getApplicationScope( SYSTEM_APP_ID )); + return ei.isHealthy(); + } } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/core/src/main/java/org/apache/usergrid/corepersistence/HybridEntityManagerFactory.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/HybridEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/HybridEntityManagerFactory.java index 54a5dee..79c3d7d 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/HybridEntityManagerFactory.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/HybridEntityManagerFactory.java @@ -163,4 +163,14 @@ public class HybridEntityManagerFactory implements EntityManagerFactory, Applica public void rebuildCollectionIndex(UUID appId, String collection, ProgressObserver po) { factory.rebuildCollectionIndex(appId, collection, po); } + + @Override + public boolean verifyCollectionsModuleHealthy() { + return factory.verifyCollectionsModuleHealthy(); + } + + @Override + public boolean verifyQueryIndexModuleHealthy() { + return factory.verifyQueryIndexModuleHealthy(); + } } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java index e57aa69..e1a22c8 100644 --- a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java +++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java @@ -130,6 +130,10 @@ public interface EntityManagerFactory { public void rebuildCollectionIndex(UUID appId, String collection, ProgressObserver object); + public boolean verifyCollectionsModuleHealthy(); + + public boolean verifyQueryIndexModuleHealthy(); + public interface ProgressObserver { public void onProgress( EntityRef entity); http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/EntityManagerFactoryImpl.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/EntityManagerFactoryImpl.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/EntityManagerFactoryImpl.java index 399bccd..2654d29 100644 --- a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/EntityManagerFactoryImpl.java +++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/EntityManagerFactoryImpl.java @@ -438,4 +438,14 @@ public class EntityManagerFactoryImpl implements EntityManagerFactory, Applicati public void rebuildCollectionIndex(UUID appId, String collection, ProgressObserver po) { throw new UnsupportedOperationException("Not supported."); } + + @Override + public boolean verifyCollectionsModuleHealthy() { + return true; + } + + @Override + public boolean verifyQueryIndexModuleHealthy() { + return true; + } } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java index f976cb5..360d8e0 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java @@ -21,18 +21,14 @@ package org.apache.usergrid.persistence.collection; import java.util.Collection; -import java.util.UUID; import org.apache.usergrid.persistence.model.entity.Entity; import org.apache.usergrid.persistence.model.entity.Id; - import org.apache.usergrid.persistence.model.field.Field; import rx.Observable; /** - * * The operations for performing changes on an entity - * */ public interface EntityCollectionManager { @@ -83,4 +79,10 @@ public interface EntityCollectionManager { * @return */ public Observable<Entity> update ( Entity entity ); + + /** + * Return true if connection query index system (Cassandra) is healthy. + */ + public boolean isHealthy(); + } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java index 9f3c1ea..f24334e 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java @@ -19,8 +19,6 @@ package org.apache.usergrid.persistence.collection.impl; -import java.net.ConnectException; -import java.util.*; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -29,7 +27,6 @@ import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; import org.apache.usergrid.persistence.collection.serialization.UniqueValue; import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; import org.apache.usergrid.persistence.collection.serialization.UniqueValueSet; -import org.apache.usergrid.persistence.model.entity.SimpleId; import org.apache.usergrid.persistence.model.field.Field; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +35,6 @@ import org.apache.usergrid.persistence.collection.CollectionScope; import org.apache.usergrid.persistence.collection.EntityCollectionManager; import org.apache.usergrid.persistence.collection.EntitySet; import org.apache.usergrid.persistence.collection.VersionSet; -import org.apache.usergrid.persistence.collection.guice.CollectionTaskExecutor; import org.apache.usergrid.persistence.collection.guice.Write; import org.apache.usergrid.persistence.collection.guice.WriteUpdate; import org.apache.usergrid.persistence.collection.mvcc.MvccEntitySerializationStrategy; @@ -53,8 +49,6 @@ import org.apache.usergrid.persistence.collection.mvcc.stage.write.WriteCommit; import org.apache.usergrid.persistence.collection.mvcc.stage.write.WriteOptimisticVerify; import org.apache.usergrid.persistence.collection.mvcc.stage.write.WriteStart; import org.apache.usergrid.persistence.collection.mvcc.stage.write.WriteUniqueVerify; -import org.apache.usergrid.persistence.collection.service.UUIDService; -import org.apache.usergrid.persistence.core.task.TaskExecutor; import org.apache.usergrid.persistence.core.util.ValidationUtils; import org.apache.usergrid.persistence.model.entity.Entity; import org.apache.usergrid.persistence.model.entity.Id; @@ -63,6 +57,12 @@ import org.apache.usergrid.persistence.model.util.UUIDGenerator; import com.google.common.base.Preconditions; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; +import com.netflix.astyanax.Keyspace; +import com.netflix.astyanax.connectionpool.OperationResult; +import com.netflix.astyanax.model.ColumnFamily; +import com.netflix.astyanax.model.CqlResult; +import com.netflix.astyanax.serializers.StringSerializer; +import org.apache.usergrid.persistence.collection.serialization.SerializationFig; import rx.Observable; import rx.Subscriber; @@ -78,10 +78,9 @@ import rx.schedulers.Schedulers; */ public class EntityCollectionManagerImpl implements EntityCollectionManager { - private static final Logger log = LoggerFactory.getLogger(EntityCollectionManagerImpl.class); + private static final Logger logger = LoggerFactory.getLogger(EntityCollectionManagerImpl.class); private final CollectionScope collectionScope; - private final UUIDService uuidService; //start stages @@ -97,32 +96,32 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { private final MarkStart markStart; private final MarkCommit markCommit; - private final TaskExecutor taskExecutor; - private final MvccLogEntrySerializationStrategy mvccLogEntrySerializationStrategy; private final MvccEntitySerializationStrategy entitySerializationStrategy; - private UniqueValueSerializationStrategy uniqueValueSerializationStrategy; + private final UniqueValueSerializationStrategy uniqueValueSerializationStrategy; + + private final Keyspace keyspace; + private SerializationFig config; @Inject - public EntityCollectionManagerImpl(final UUIDService uuidService, @Write final WriteStart writeStart, - @WriteUpdate final WriteStart writeUpdate, - final WriteUniqueVerify writeVerifyUnique, - final WriteOptimisticVerify writeOptimisticVerify, - final WriteCommit writeCommit, final RollbackAction rollback, - final MarkStart markStart, final MarkCommit markCommit, - final MvccEntitySerializationStrategy entitySerializationStrategy, - final UniqueValueSerializationStrategy uniqueValueSerializationStrategy, - final MvccLogEntrySerializationStrategy mvccLogEntrySerializationStrategy, - @CollectionTaskExecutor final TaskExecutor taskExecutor, - @Assisted final CollectionScope collectionScope + public EntityCollectionManagerImpl( + @Write final WriteStart writeStart, + @WriteUpdate final WriteStart writeUpdate, + final WriteUniqueVerify writeVerifyUnique, + final WriteOptimisticVerify writeOptimisticVerify, + final WriteCommit writeCommit, final RollbackAction rollback, + final MarkStart markStart, final MarkCommit markCommit, + final MvccEntitySerializationStrategy entitySerializationStrategy, + final UniqueValueSerializationStrategy uniqueValueSerializationStrategy, + final MvccLogEntrySerializationStrategy mvccLogEntrySerializationStrategy, + final Keyspace keyspace, + final SerializationFig config, + @Assisted final CollectionScope collectionScope ) { this.uniqueValueSerializationStrategy = uniqueValueSerializationStrategy; this.entitySerializationStrategy = entitySerializationStrategy; - - Preconditions.checkNotNull(uuidService, "uuidService must be defined"); - MvccValidationUtils.validateCollectionScope(collectionScope); this.writeStart = writeStart; @@ -136,9 +135,10 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { this.markStart = markStart; this.markCommit = markCommit; - this.uuidService = uuidService; + this.keyspace = keyspace; + this.config = config; + this.collectionScope = collectionScope; - this.taskExecutor = taskExecutor; this.mvccLogEntrySerializationStrategy = mvccLogEntrySerializationStrategy; } @@ -187,12 +187,12 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { Preconditions.checkNotNull(entityId.getType(), "Entity type is required in this stage"); return Observable.from(new CollectionIoEvent<Id>(collectionScope, entityId)).map(markStart) - .doOnNext(markCommit).map(new Func1<CollectionIoEvent<MvccEntity>, Void>() { - @Override - public Void call(final CollectionIoEvent<MvccEntity> mvccEntityCollectionIoEvent) { - return null; - } - }); + .doOnNext(markCommit).map(new Func1<CollectionIoEvent<MvccEntity>, Void>() { + @Override + public Void call(final CollectionIoEvent<MvccEntity> mvccEntityCollectionIoEvent) { + return null; + } + }); } @@ -229,8 +229,8 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { @Override public void call(final Subscriber<? super EntitySet> subscriber) { try { - final EntitySet results = - entitySerializationStrategy.load(collectionScope, entityIds, UUIDGenerator.newTimeUUID()); + final EntitySet results = entitySerializationStrategy.load( + collectionScope, entityIds, UUIDGenerator.newTimeUUID()); subscriber.onNext(results); subscriber.onCompleted(); @@ -253,7 +253,7 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { Id id = value == null ? null : value.getEntityId(); return id; } catch (ConnectionException e) { - log.error("Failed to getIdField", e); + logger.error("Failed to getIdField", e); throw new RuntimeException(e); } } @@ -263,7 +263,7 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { @Override public Observable<Entity> update(final Entity entity) { - log.debug("Starting update process"); + logger.debug("Starting update process"); //do our input validation Preconditions.checkNotNull(entity, "Entity is required in the new stage of the mvcc write"); @@ -283,7 +283,7 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { return observable.map(writeCommit).doOnNext(new Action1<Entity>() { @Override public void call(final Entity entity) { - log.debug("sending entity to the queue"); + logger.debug("sending entity to the queue"); //we an update, signal the fix @@ -301,7 +301,8 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { public Observable<CollectionIoEvent<MvccEntity>> stageRunner(CollectionIoEvent<Entity> writeData, WriteStart writeState) { - return Observable.from(writeData).map(writeState).doOnNext(new Action1<CollectionIoEvent<MvccEntity>>() { + return Observable.from(writeData).map(writeState).doOnNext( + new Action1<CollectionIoEvent<MvccEntity>>() { @Override public void call(final CollectionIoEvent<MvccEntity> mvccEntityCollectionIoEvent) { @@ -325,7 +326,6 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { @Override - public Observable<VersionSet> getLatestVersion(final Collection<Id> entityIds) { return Observable.create(new Observable.OnSubscribe<VersionSet>() { @@ -345,4 +345,31 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager { } }); } + + + @Override + public boolean isHealthy() { + + try { + ColumnFamily<String, String> CF_SYSTEM_LOCAL = new ColumnFamily<String, String>( + "system.local", + StringSerializer.get(), + StringSerializer.get(), + StringSerializer.get()); + + OperationResult<CqlResult<String, String>> result = keyspace.prepareQuery(CF_SYSTEM_LOCAL) + .withCql("SELECT now() FROM system.local;") + .execute(); + + if ( result.getResult().getRows().size() == 1 ) { + return true; + } + + } catch ( ConnectionException ex ) { + logger.error("Error connecting to Cassandra", ex); + } + + return false; + } + } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java index 15bae5c..294c7ab 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java @@ -59,20 +59,16 @@ public interface SerializationFig extends GuicyFig { /** * The maximum amount of entites we can load at any one time - * @return */ @Key( "collection.max.load.size" ) @Default( "1000" ) int getMaxLoadSize(); - /** * The maximum number of bytes a serialized entity can be. Any thing beyond this is rejected - * @return */ @Key( "collection.max.entry.size" ) @Default( "512" ) int getMaxEntrySize(); - } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java index 93f4a7d..763d00a 100644 --- a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java +++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java @@ -694,4 +694,16 @@ public class EntityCollectionManagerIT { assertEquals( MvccLogEntry.State.COMPLETE, version2Log.getState() ); assertEquals( Stage.COMMITTED, version2Log.getStage() ); } + + + @Test + public void healthTest() { + + CollectionScope context = new CollectionScopeImpl( + new SimpleId( "organization" ), new SimpleId( "test" ), "test" ); + + final EntityCollectionManager manager = factory.createCollectionManager( context ); + + assertTrue( manager.isHealthy() ); + } } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java index 5f4606c..fda3a53 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java @@ -36,27 +36,27 @@ public interface EntityIndex { public void initializeIndex(); /** - * Create the index batch - * @return + * Create the index batch. */ public EntityIndexBatch createBatch(); /** * Execute query in Usergrid syntax. */ - public CandidateResults search(final IndexScope indexScope, Query query ); /** - * Get the candidate results of all versions of the entity for this id - * @param id - * @return + * Get the candidate results of all versions of the entity for this id. */ public CandidateResults getEntityVersions(final IndexScope indexScope, Id id); /** - * Refresh the index + * Refresh the index. */ public void refresh(); + /** + * Return true if connection query index system (ElasticSearch) is healthy. + */ + public boolean isHealthy(); } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java index fc09b5a..1ff747f 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java @@ -64,12 +64,16 @@ import org.apache.usergrid.persistence.model.util.UUIDGenerator; import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; +import java.util.concurrent.ExecutionException; import static org.apache.usergrid.persistence.index.impl.IndexingUtils.BOOLEAN_PREFIX; import static org.apache.usergrid.persistence.index.impl.IndexingUtils.DOC_ID_SEPARATOR_SPLITTER; import static org.apache.usergrid.persistence.index.impl.IndexingUtils.ENTITYID_FIELDNAME; import static org.apache.usergrid.persistence.index.impl.IndexingUtils.NUMBER_PREFIX; import static org.apache.usergrid.persistence.index.impl.IndexingUtils.STRING_PREFIX; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; /** @@ -77,7 +81,7 @@ import static org.apache.usergrid.persistence.index.impl.IndexingUtils.STRING_PR */ public class EsEntityIndexImpl implements EntityIndex { - private static final Logger log = LoggerFactory.getLogger( EsEntityIndexImpl.class ); + private static final Logger logger = LoggerFactory.getLogger( EsEntityIndexImpl.class ); private static final AtomicBoolean mappingsCreated = new AtomicBoolean( false ); @@ -128,13 +132,13 @@ public class EsEntityIndexImpl implements EntityIndex { AdminClient admin = client.admin(); CreateIndexResponse cir = admin.indices().prepareCreate( indexName ).execute().actionGet(); - log.info( "Created new Index Name [{}] ACK=[{}]", indexName, cir.isAcknowledged() ); + logger.info( "Created new Index Name [{}] ACK=[{}]", indexName, cir.isAcknowledged() ); // create the document, this ensures the index is ready // Immediately create a document and remove it to ensure the entire cluster is ready - // to receive documents. Occasionally we see errors. See this post: - // http://elasticsearch-users.115913.n3.nabble.com/IndexMissingException-on-create-index-followed-by-refresh-td1832793.html + // to receive documents. Occasionally we see errors. + // See this post: http://s.apache.org/index-missing-exception testNewIndex(); } @@ -148,16 +152,13 @@ public class EsEntityIndexImpl implements EntityIndex { /** - * Tests writing a document to a new index to ensure it's working correctly. Comes from email - * - * http://elasticsearch-users.115913.n3.nabble - * .com/IndexMissingException-on-create-index-followed-by-refresh-td1832793.html + * Tests writing a document to a new index to ensure it's working correctly. + * See this post: http://s.apache.org/index-missing-exception */ - private void testNewIndex() { - log.info( "Refreshing Created new Index Name [{}]", indexName ); + logger.info( "Refreshing Created new Index Name [{}]", indexName ); final RetryOperation retryOperation = new RetryOperation() { @Override @@ -167,14 +168,14 @@ public class EsEntityIndexImpl implements EntityIndex { client.prepareIndex( indexName, VERIFY_TYPE, tempId ) .setSource( DEFAULT_PAYLOAD ).get(); - log.info( "Successfully created new document with docId {} in index {} and type {}", + logger.info( "Successfully created new document with docId {} in index {} and type {}", tempId, indexName, VERIFY_TYPE ); // delete all types, this way if we miss one it will get cleaned up client.prepareDeleteByQuery( indexName ).setTypes( VERIFY_TYPE ) .setQuery( MATCH_ALL_QUERY_BUILDER ).get(); - log.info( "Successfully deleted all documents in index {} and type {}", + logger.info( "Successfully deleted all documents in index {} and type {}", indexName, VERIFY_TYPE ); return true; @@ -215,8 +216,8 @@ public class EsEntityIndexImpl implements EntityIndex { QueryBuilder qb = query.createQueryBuilder(); - if ( log.isDebugEnabled() ) { - log.debug( "Searching index {}\n type {}\n query {} limit {}", new Object[] { + if ( logger.isDebugEnabled() ) { + logger.debug( "Searching index {}\n type {}\n query {} limit {}", new Object[] { this.indexName, indexType, qb.toString().replace( "\n", " " ), query.getLimit() } ); } @@ -229,7 +230,7 @@ public class EsEntityIndexImpl implements EntityIndex { FilterBuilder fb = query.createFilterBuilder(); if ( fb != null ) { - log.debug( " Filter: {} ", fb.toString() ); + logger.debug( " Filter: {} ", fb.toString() ); srb = srb.setPostFilter( fb ); } @@ -254,19 +255,19 @@ public class EsEntityIndexImpl implements EntityIndex { final FieldSortBuilder stringSort = SortBuilders.fieldSort( stringFieldName ) .order( order ).ignoreUnmapped( true ); srb.addSort( stringSort ); - log.debug( " Sort: {} order by {}", stringFieldName, order.toString() ); + logger.debug( " Sort: {} order by {}", stringFieldName, order.toString() ); final String numberFieldName = NUMBER_PREFIX + sp.getPropertyName(); final FieldSortBuilder numberSort = SortBuilders.fieldSort( numberFieldName ) .order( order ).ignoreUnmapped( true ); srb.addSort( numberSort ); - log.debug( " Sort: {} order by {}", numberFieldName, order.toString() ); + logger.debug( " Sort: {} order by {}", numberFieldName, order.toString() ); final String booleanFieldName = BOOLEAN_PREFIX + sp.getPropertyName(); final FieldSortBuilder booleanSort = SortBuilders.fieldSort( booleanFieldName ) .order( order ).ignoreUnmapped( true ); srb.addSort( booleanSort ); - log.debug( " Sort: {} order by {}", booleanFieldName, order.toString() ); + logger.debug( " Sort: {} order by {}", booleanFieldName, order.toString() ); } searchResponse = srb.execute().actionGet(); @@ -279,7 +280,7 @@ public class EsEntityIndexImpl implements EntityIndex { if ( scrollId.endsWith( "\"" ) ) { scrollId = scrollId.substring( 0, scrollId.length() - 1 ); } - log.debug( "Executing query with cursor: {} ", scrollId ); + logger.debug( "Executing query with cursor: {} ", scrollId ); SearchScrollRequestBuilder ssrb = client.prepareSearchScroll( scrollId ) .setScroll( cursorTimeout + "m" ); @@ -287,7 +288,7 @@ public class EsEntityIndexImpl implements EntityIndex { } SearchHits hits = searchResponse.getHits(); - log.debug( " Hit count: {} Total hits: {}", hits.getHits().length, hits.getTotalHits() ); + logger.debug( " Hit count: {} Total hits: {}", hits.getHits().length, hits.getTotalHits() ); List<CandidateResult> candidates = new ArrayList<CandidateResult>(); @@ -307,7 +308,7 @@ public class EsEntityIndexImpl implements EntityIndex { if ( candidates.size() >= query.getLimit() ) { candidateResults.setCursor( searchResponse.getScrollId() ); - log.debug( " Cursor = " + searchResponse.getScrollId() ); + logger.debug( " Cursor = " + searchResponse.getScrollId() ); } return candidateResults; @@ -317,18 +318,18 @@ public class EsEntityIndexImpl implements EntityIndex { public void refresh() { - log.info( "Refreshing Created new Index Name [{}]", indexName ); + logger.info( "Refreshing Created new Index Name [{}]", indexName ); final RetryOperation retryOperation = new RetryOperation() { @Override public boolean doOp() { try { client.admin().indices().prepareRefresh( indexName ).execute().actionGet(); - log.debug( "Refreshed index: " + indexName ); + logger.debug( "Refreshed index: " + indexName ); return true; } catch ( IndexMissingException e ) { - log.error( "Unable to refresh index after create. Waiting before sleeping.", e); + logger.error( "Unable to refresh index after create. Waiting before sleeping.", e); throw e; } } @@ -336,7 +337,7 @@ public class EsEntityIndexImpl implements EntityIndex { doInRetry( retryOperation ); - log.debug( "Refreshed index: " + indexName ); + logger.debug( "Refreshed index: " + indexName ); } @@ -356,10 +357,10 @@ public class EsEntityIndexImpl implements EntityIndex { AdminClient adminClient = client.admin(); DeleteIndexResponse response = adminClient.indices().prepareDelete( indexName ).get(); if ( response.isAcknowledged() ) { - log.info( "Deleted index: " + indexName ); + logger.info( "Deleted index: " + indexName ); } else { - log.info( "Failed to delete index " + indexName ); + logger.info( "Failed to delete index " + indexName ); } } @@ -377,7 +378,7 @@ public class EsEntityIndexImpl implements EntityIndex { } } catch ( Exception e ) { - log.error( "Unable to execute operation, retrying", e ); + logger.error( "Unable to execute operation, retrying", e ); } @@ -391,6 +392,25 @@ public class EsEntityIndexImpl implements EntityIndex { } + @Override + public boolean isHealthy() { + + try { + ClusterHealthResponse health = + client.admin().cluster().health( new ClusterHealthRequest() ).get(); + + if ( health.getStatus().equals( ClusterHealthStatus.GREEN ) ) { + return true; + } + } + catch (Exception ex) { + logger.error("Error connecting to ElasticSearch", ex); + } + + return false ; + } + + /** * Interface for operations */ http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java index 62910bc..28b3bfb 100644 --- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java +++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java @@ -50,9 +50,11 @@ import org.apache.usergrid.persistence.model.entity.SimpleId; import org.apache.usergrid.persistence.model.util.UUIDGenerator; import com.google.inject.Inject; +import org.apache.usergrid.persistence.collection.EntityCollectionManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; @RunWith( ITRunner.class ) @@ -82,7 +84,8 @@ public class EntityConnectionIndexImplTest extends BaseIT { // create a muffin CollectionScope muffinScope = new CollectionScopeImpl( appId, appId, "muffins" ); - Entity muffin = new Entity( new SimpleId( UUIDGenerator.newTimeUUID(), muffinScope.getName() ) ); + Entity muffin = new Entity( + new SimpleId( UUIDGenerator.newTimeUUID(), muffinScope.getName() ) ); muffin = EntityIndexMapUtils.fromMap( muffin, new HashMap<String, Object>() {{ put( "size", "Large" ); @@ -93,7 +96,8 @@ public class EntityConnectionIndexImplTest extends BaseIT { // create a person who likes muffins CollectionScope peopleScope = new CollectionScopeImpl( appId, appId, "people" ); - Entity person = new Entity( new SimpleId( UUIDGenerator.newTimeUUID(), peopleScope.getName() ) ); + Entity person = new Entity( new SimpleId( + UUIDGenerator.newTimeUUID(), peopleScope.getName() ) ); person = EntityIndexMapUtils.fromMap( person, new HashMap<String, Object>() {{ put( "name", "Dave" ); put( "hometown", "Chapel Hill" ); @@ -121,4 +125,18 @@ public class EntityConnectionIndexImplTest extends BaseIT { assertEquals(muffin.getId(), likes.get(0).getId()); } + + + + @Test + public void healthTest() { + + Id appId = new SimpleId( "application" ); + ApplicationScope applicationScope = new ApplicationScopeImpl( appId ); + + EntityIndex ei = ecif.createEntityIndex( applicationScope ); + + assertTrue( ei.isHealthy() ); + } + } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/loadtests/src/test/resources/logback-test.xml ---------------------------------------------------------------------- diff --git a/stack/loadtests/src/test/resources/logback-test.xml b/stack/loadtests/src/test/resources/logback-test.xml index d15f9f4..f3f0607 100644 --- a/stack/loadtests/src/test/resources/logback-test.xml +++ b/stack/loadtests/src/test/resources/logback-test.xml @@ -1,3 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> <configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/loadtests/src/test/resources/logback.xml ---------------------------------------------------------------------- diff --git a/stack/loadtests/src/test/resources/logback.xml b/stack/loadtests/src/test/resources/logback.xml index 1d512d6..6ba218c 100644 --- a/stack/loadtests/src/test/resources/logback.xml +++ b/stack/loadtests/src/test/resources/logback.xml @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> -<configuration> <!-- /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -18,6 +17,8 @@ * limitations under the License. */ --> +<configuration> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern> http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/rest/src/main/java/org/apache/usergrid/rest/SwaggerServlet.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/SwaggerServlet.java b/stack/rest/src/main/java/org/apache/usergrid/rest/SwaggerServlet.java index 576063e..9db6ff4 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/SwaggerServlet.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/SwaggerServlet.java @@ -41,9 +41,9 @@ import org.springframework.context.ApplicationContext; import org.apache.commons.lang.text.StrSubstitutor; import static org.apache.commons.lang.StringUtils.isEmpty; -import static org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext; import static org.apache.usergrid.rest.utils.CORSUtils.allowAllOrigins; import static org.apache.usergrid.utils.StringUtils.readClasspathFileAsString; +import org.springframework.web.context.support.WebApplicationContextUtils; public class SwaggerServlet extends HttpServlet implements Filter { @@ -85,7 +85,8 @@ public class SwaggerServlet extends HttpServlet implements Filter { if ( sc == null ) { return null; } - ApplicationContext appContext = getRequiredWebApplicationContext( sc ); + ApplicationContext appContext = + WebApplicationContextUtils.getRequiredWebApplicationContext( sc ); return appContext.getBean( beanName ); } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/rest/src/main/java/org/apache/usergrid/rest/filters/HealthCheckFilter.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/filters/HealthCheckFilter.java b/stack/rest/src/main/java/org/apache/usergrid/rest/filters/HealthCheckFilter.java new file mode 100644 index 0000000..4ba9b09 --- /dev/null +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/filters/HealthCheckFilter.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.filters; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.usergrid.persistence.EntityManagerFactory; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + + +/** + * Fail fast if connection to database or query index not healthy. + */ +public class HealthCheckFilter implements Filter { + + ServletContext sc; + + @Override + public void init(FilterConfig fc) throws ServletException { + if ( sc == null ) { + sc = fc.getServletContext(); + } + } + + @Override + public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) + throws IOException, ServletException { + + + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc); + EntityManagerFactory emf = (EntityManagerFactory)ctx.getBean("entityManagerFactory"); + + if ( !emf.verifyCollectionsModuleHealthy() ) { + throw new RuntimeException("Error connecting to datastore"); + } + if ( !emf.verifyQueryIndexModuleHealthy() ) { + throw new RuntimeException("Error connecting to query index"); + } + + throw new RuntimeException("Foo!"); + } + + @Override + public void destroy() { + // no op + } + +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b6a8bc62/stack/rest/src/main/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/webapp/WEB-INF/web.xml b/stack/rest/src/main/webapp/WEB-INF/web.xml index 24a82ca..c50251b 100644 --- a/stack/rest/src/main/webapp/WEB-INF/web.xml +++ b/stack/rest/src/main/webapp/WEB-INF/web.xml @@ -33,6 +33,16 @@ </listener> <filter> + <filter-name>healthCheckFilter</filter-name> + <filter-class>org.apache.usergrid.rest.filters.HealthCheckFilter</filter-class> + </filter> + + <filter-mapping> + <filter-name>healthCheckFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter> <filter-name>swaggerFilter</filter-name> <filter-class>org.apache.usergrid.rest.SwaggerServlet</filter-class> </filter>
