Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Liveness: The misleading `Internal error` description for suspended liveness has been replaced with the proper `Service unavailable` message.
1 change: 1 addition & 0 deletions common/src/main/resources/i18n/translations_de.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
error=Fehler
error_internal=Interner Fehler aufgetreten.
error_service_unavailable=Das Service ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut.
error_invalid_parameter=Falscher Inhalt "{1}" des Parameters "{0}".
error_not_authorized=Sie sind nicht berechtigt um auf die angefragte Resource zuzugreifen.
error_admin_permission_required=Es werden Administrator Rechte benötigt.
Expand Down
1 change: 1 addition & 0 deletions common/src/main/resources/i18n/translations_en.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
error=Error
error_internal=Internal error occurred.
error_service_unavailable=Service is unavailable at the moment. Please try again later.
error_invalid_parameter=Invalid "{0}" parameter value "{1}".
error_not_authorized=You are not authorized to access the requested resource.
error_admin_permission_required=Administration permissions are required.
Expand Down
1 change: 1 addition & 0 deletions common/src/main/resources/i18n/translations_zh.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
error=错误
error_internal=发生内部错误。
error_service_unavailable=该服务目前无法使用。请稍后再试。
error_invalid_parameter=“{0}”参数值“{1}”无效。
error_not_authorized=你无权访问所请求的资源。
error_admin_permission_required=需要管理权限。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void handleLive(RoutingContext rc) {
PluginStatus status = pluginManager.getStatus(id);
if (status == PluginStatus.FAILED) {
log.warn("Plugin {" + id + "} is in status failed.");
throw error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false);
throw error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false);
}
}
if (!liveness.isLive()) {
Expand All @@ -72,7 +72,7 @@ public void handleLive(RoutingContext rc) {
break;
default:
log.warn("Liveness was set to false due to {}", liveness.getError());
throw error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false);
throw error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false);
}
}
rc.response().setStatusCode(200).end();
Expand All @@ -87,7 +87,7 @@ public void handleReady(RoutingContext rc) {
MeshStatus status = boot.mesh().getStatus();
if (!status.equals(MeshStatus.READY)) {
log.warn("Status is {" + status.name() + "} - Failing readiness probe");
throw error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false);
throw error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false);
}
for (String id : pluginManager.getPluginIds()) {
PluginStatus pluginStatus = pluginManager.getStatus(id);
Expand All @@ -99,16 +99,16 @@ public void handleReady(RoutingContext rc) {
// be reached.
if (pluginStatus == PluginStatus.FAILED) {
log.error("Plugin {" + id + "} is in status failed.");
throw error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false);
throw error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false);
}
}
if (!liveness.isLive()) {
log.warn("Liveness was set to false due to {}", liveness.getError());
throw error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false);
throw error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false);
}
if (!db.isHealthy()) {
log.warn("Failing DB health check");
throw error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false);
throw error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false);
}
rc.response().end();
}
Expand All @@ -123,18 +123,18 @@ public void handleReady(RoutingContext rc) {
*/
public void handleWritable(RoutingContext rc) {
localConfigApi.getActiveConfig()
.map(LocalConfigModel::isReadOnly)
.map(Boolean::booleanValue)
.subscribe(isReadOnly -> {
if (isReadOnly) {
log.warn("Local node cannot write - read only mode set");
rc.fail(error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false));
} else if (db.isReadOnly(false)) {
log.warn("Local node cannot write - read only database");
rc.fail(error(SERVICE_UNAVAILABLE, "error_internal").setLogStackTrace(false));
} else {
rc.response().setStatusCode(200).end();
}
});
.map(LocalConfigModel::isReadOnly)
.map(Boolean::booleanValue)
.subscribe(isReadOnly -> {
if (isReadOnly) {
log.warn("Local node cannot write - read only mode set");
rc.fail(error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false));
} else if (db.isReadOnly(false)) {
log.warn("Local node cannot write - read only database");
rc.fail(error(SERVICE_UNAVAILABLE, "error_service_unavailable").setLogStackTrace(false));
} else {
rc.response().setStatusCode(200).end();
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public enum MeshCoreOptionChanger implements MeshOptionChanger {
options.getUploadOptions().setCheckInterval(5_000);
}), SHORT_MIGRATION_BATCH(options -> {
options.setMigrationMaxBatchSize(2);
}), SMALL_EVENT_LOOP_POOL(options -> {
options.getVertxOptions().setEventPoolSize(1);
});

private final Consumer<MeshOptions> changer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.gentics.mesh.core;

import java.util.concurrent.CountDownLatch;

import org.junit.Test;
import org.junit.experimental.categories.Category;

import com.gentics.mesh.test.MeshCoreOptionChanger;
import com.gentics.mesh.test.MeshTestSetting;
import com.gentics.mesh.test.TestSize;
import com.gentics.mesh.test.category.FailingTests;
import com.gentics.mesh.test.context.AbstractMeshTest;

@MeshTestSetting(testSize = TestSize.PROJECT, startServer = true, optionChanger = MeshCoreOptionChanger.SMALL_EVENT_LOOP_POOL)
@Category(FailingTests.class)
public class ResponsivenessTest extends AbstractMeshTest {

@Test
public void testBlockingGets() throws InterruptedException {
int numThreads = 100;
CountDownLatch latch = new CountDownLatch(numThreads);
for (int i = 0; i < numThreads; i++) {
new Thread(() -> {
client().me().blockingGet();
latch.countDown();
}).start();
}
latch.await();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.gentics.mesh.core.admin;

import static com.gentics.mesh.MeshVersion.CURRENT_API_BASE_PATH;
import static com.gentics.mesh.test.TestSize.PROJECT;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.experimental.categories.Category;

import com.gentics.mesh.core.rest.error.GenericRestException;
import com.gentics.mesh.core.rest.user.UserResponse;
import com.gentics.mesh.json.JsonUtil;
import com.gentics.mesh.plugin.AbstractPluginTest;
import com.gentics.mesh.test.MeshCoreOptionChanger;
import com.gentics.mesh.test.MeshTestSetting;
import com.gentics.mesh.test.category.PluginTests;

@Category(PluginTests.class)
@MeshTestSetting(testSize = PROJECT, startServer = true, inMemoryDB = true, optionChanger = MeshCoreOptionChanger.SMALL_EVENT_LOOP_POOL)
public class PluginConnectivityResponsivenessTest extends AbstractPluginTest {

@Test
public void testClientPlugin() throws IOException, InterruptedException {
grantAdmin();

copyAndDeploy(CLIENT_PATH, "client.jar");
assertEquals(1, pluginManager().getPluginIds().size());

int numRequests = 50;
CountDownLatch latch = new CountDownLatch(numRequests);
for (int i = 0; i < numRequests; i++) {
new Thread(() -> {
try {
assertNotNull("Should find a default John Doe user", JsonUtil.readValue(httpGetNow(CURRENT_API_BASE_PATH + "/plugins/client/me"), UserResponse.class));
latch.countDown();
} catch (GenericRestException | IOException e) {
throw new IllegalStateException(e);
}
}).start();
}
latch.await(10, TimeUnit.SECONDS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void testWritableReturns200() {
@Test
public void testWritableReturns503WhenReadOnlyMode() {
call(() -> client().updateLocalConfig(buildLocalConfigModel(true)));
call(() -> monClient().writable(), SERVICE_UNAVAILABLE, "error_internal");
call(() -> monClient().writable(), SERVICE_UNAVAILABLE, "error_service_unavailable");
}

private LocalConfigModel buildLocalConfigModel(boolean readOnly) {
Expand Down