From 4b9ff6b1095faf208928558099e5292f14ca9dc1 Mon Sep 17 00:00:00 2001 From: Rajesh Rathnam Date: Tue, 5 May 2020 18:56:47 +0530 Subject: [PATCH] SC-000 Merge 2.10.0 to master (#397) * SC-1676 Update .gitmodules (#386) * Issue #SB-18059 feat: code to handle ClientErrorREsponse (#387) * Issue #SB-18059 feat: code to handle ClientErrorREsponse * Issue #SB-18059 feta:fixed indentation * Issue #SC-1707 removed unused dependencies (#388) * Issue #SC-1707 removed unused dependencies * Issue #SC-1707 changing sub-module in order to test functional test cases in dev * Issue #SC-1707 reverting back the sub-module changes * Issue #SC-1707 added space for build failure * Issue #SC-1707 removed space for build failure * Issue #SC-1707 dependent module uncommented * Issue #SC-1745 feat: update git module file (#389) * Issue #SC-1722 feat: handling SIGTERM singnal for gracefull shutdown (#390) * Issue #SC-1722 feat: handling SIGTERM singnal for gracefull shutdown * Issue #SC-1745 feat: update git module file * Create auto_build_deploy * Update auto_build_deploy * Update auto_build_deploy * Issue #SB-18958 Roll forward from 2.8.0_RC6 tag (#393) * Issue #SB-18958 release-2.10 is merged with latest changes * Issue #SB-18958 log line change in Basecontroller * Issue #SB-18958 adding dummy commit * Issue #SB-19078 Redeploy - commit (#395) * SC-1789 Commonise log msg (#396) Co-authored-by: indrajra-ilimi * SC-000 Update .gitmodules Co-authored-by: AMIT KUMAR Co-authored-by: Hari-stackroute <40484996+Hari-stackroute@users.noreply.github.com> Co-authored-by: G33tha Co-authored-by: amorphous-1 Co-authored-by: indrajra-ilimi --- .gitmodules | 2 +- Dockerfile | 2 +- auto_build_deploy | 63 +++++ pom.xml | 11 + service/app/controllers/BaseController.java | 266 +++++++++++------- .../healthmanager/HealthController.java | 47 +++- service/app/modules/SignalHandler.java | 48 ++++ service/app/modules/StartModule.java | 1 + service/pom.xml | 52 ---- setupRepo.sh | 0 10 files changed, 320 insertions(+), 172 deletions(-) create mode 100644 auto_build_deploy create mode 100644 service/app/modules/SignalHandler.java create mode 100644 setupRepo.sh diff --git a/.gitmodules b/.gitmodules index c8dd41149d..67e9f8925d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "actors/sunbird-lms-mw"] path = actors/sunbird-lms-mw url = https://github.com/project-sunbird/sunbird-lms-mw.git - branch = master + branch = master diff --git a/Dockerfile b/Dockerfile index 43b1e8c110..8522ff90f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,4 +12,4 @@ USER sunbird COPY ./service/target/learning-service-1.0-SNAPSHOT-dist.zip /home/sunbird/learner/ RUN unzip /home/sunbird/learner/learning-service-1.0-SNAPSHOT-dist.zip -d /home/sunbird/learner/ WORKDIR /home/sunbird/learner/ -CMD java -cp '/home/sunbird/learner/learning-service-1.0-SNAPSHOT/lib/*' play.core.server.ProdServerStart /home/sunbird/learner/learning-service-1.0-SNAPSHOT +CMD java -XX:+PrintFlagsFinal $JAVA_OPTIONS -cp '/home/sunbird/learner/learning-service-1.0-SNAPSHOT/lib/*' play.core.server.ProdServerStart /home/sunbird/learner/learning-service-1.0-SNAPSHOT diff --git a/auto_build_deploy b/auto_build_deploy new file mode 100644 index 0000000000..9731316431 --- /dev/null +++ b/auto_build_deploy @@ -0,0 +1,63 @@ +@Library('deploy-conf') _ +node('build-slave') { + try { + String ANSI_GREEN = "\u001B[32m" + String ANSI_NORMAL = "\u001B[0m" + String ANSI_BOLD = "\u001B[1m" + String ANSI_RED = "\u001B[31m" + String ANSI_YELLOW = "\u001B[33m" + + ansiColor('xterm') { + stage('Checkout') { + tag_name = env.JOB_NAME.split("/")[-1] + pre_checks() + if (!env.hub_org) { + println(ANSI_BOLD + ANSI_RED + "Uh Oh! Please set a Jenkins environment variable named hub_org with value as registery/sunbidrded" + ANSI_NORMAL) + error 'Please resolve the errors and rerun..' + } else + println(ANSI_BOLD + ANSI_GREEN + "Found environment variable named hub_org with value as: " + hub_org + ANSI_NORMAL) + } + cleanWs() + def scmVars = checkout scm + checkout scm: [$class: 'GitSCM', branches: [[name: "refs/tags/$tag_name"]], userRemoteConfigs: [[url: scmVars.GIT_URL]]] + build_tag = tag_name + "_" + env.BUILD_NUMBER + commit_hash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() + artifact_version = tag_name + "_" + commit_hash + echo "build_tag: " + build_tag + + // stage Build + env.NODE_ENV = "build" + print "Environment will be : ${env.NODE_ENV}" + sh('git submodule update --init') + sh('git submodule update --init --recursive --remote') + sh 'git log -1' + sh 'cat service/conf/routes | grep v2' + sh 'mvn clean install -U -DskipTests=true ' + + + // stage Unit Tests + sh "mvn test '-Dtest=!%regex[io.opensaber.registry.client.*]' -DfailIfNoTests=false" + + // stage Package + dir('service') { + sh 'mvn play2:dist' + } + sh('chmod 777 ./build.sh') + sh("./build.sh ${build_tag} ${env.NODE_NAME} ${hub_org}") + + // stage ArchiveArtifacts + archiveArtifacts "metadata.json" + currentBuild.description = "${build_tag}" + } + currentBuild.result = "SUCCESS" + slack_notify(currentBuild.result, tag_name) + email_notify() + auto_build_deploy() + } + catch (err) { + currentBuild.result = "FAILURE" + slack_notify(currentBuild.result, tag_name) + email_notify() + throw err + } +} diff --git a/pom.xml b/pom.xml index 09d3b82f7e..d60616c0d4 100644 --- a/pom.xml +++ b/pom.xml @@ -15,4 +15,15 @@ actors/sunbird-lms-mw service + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.1 + + + + diff --git a/service/app/controllers/BaseController.java b/service/app/controllers/BaseController.java index 7c3515dc0a..02dda98045 100644 --- a/service/app/controllers/BaseController.java +++ b/service/app/controllers/BaseController.java @@ -13,12 +13,16 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import modules.ApplicationStart; import modules.OnRequestHandler; import org.apache.commons.lang3.StringUtils; import org.sunbird.actor.service.SunbirdMWService; import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.ClientErrorResponse; import org.sunbird.common.models.response.Response; import org.sunbird.common.models.response.ResponseParams; import org.sunbird.common.models.util.ActorOperations; @@ -39,10 +43,6 @@ import play.mvc.Results; import util.AuthenticationHelper; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; - /** * This controller we can use for writing some common method. * @@ -65,9 +65,10 @@ public class BaseController extends Controller { } private org.sunbird.common.request.Request initRequest( - org.sunbird.common.request.Request request, String operation, Request httpRequest) { + org.sunbird.common.request.Request request, String operation, Request httpRequest) { request.setOperation(operation); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); + request.getParams().setMsgid(httpRequest.flash().get(JsonKey.REQUEST_ID)); request.setEnv(getEnvironment()); request.getContext().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); request = transformUserId(request); @@ -84,7 +85,7 @@ private org.sunbird.common.request.Request initRequest( * instance. */ protected org.sunbird.common.request.Request createAndInitRequest( - String operation, JsonNode requestBodyJson, Request httpRequest) { + String operation, JsonNode requestBodyJson, Request httpRequest) { org.sunbird.common.request.Request request = (org.sunbird.common.request.Request) mapper.RequestMapper.mapRequest( @@ -100,7 +101,8 @@ protected org.sunbird.common.request.Request createAndInitRequest( * @return Created and initialised Request (@see {@link org.sunbird.common.request.Request}) * instance. */ - protected org.sunbird.common.request.Request createAndInitRequest(String operation, Request httpRequest) { + protected org.sunbird.common.request.Request createAndInitRequest( + String operation, Request httpRequest) { org.sunbird.common.request.Request request = new org.sunbird.common.request.Request(); return initRequest(request, operation, httpRequest); } @@ -109,7 +111,8 @@ protected CompletionStage handleRequest(String operation, Http.Request h return handleRequest(operation, null, null, null, null, false, httpRequest); } - protected CompletionStage handleRequest(String operation, JsonNode requestBodyJson, Request httpRequest) { + protected CompletionStage handleRequest( + String operation, JsonNode requestBodyJson, Request httpRequest) { return handleRequest(operation, requestBodyJson, null, null, null, true, httpRequest); } @@ -119,41 +122,56 @@ protected CompletionStage handleRequest( } protected CompletionStage handleRequest( - String operation, JsonNode requestBodyJson, Function requestValidatorFn, Request httpRequest) { - return handleRequest(operation, requestBodyJson, requestValidatorFn, null, null, true, httpRequest); + String operation, + JsonNode requestBodyJson, + Function requestValidatorFn, + Request httpRequest) { + return handleRequest( + operation, requestBodyJson, requestValidatorFn, null, null, true, httpRequest); } - protected CompletionStage handleRequest(String operation, String pathId, String pathVariable, Request httpRequest) { + protected CompletionStage handleRequest( + String operation, String pathId, String pathVariable, Request httpRequest) { return handleRequest(operation, null, null, pathId, pathVariable, false, httpRequest); } protected CompletionStage handleRequest( - String operation, String pathId, String pathVariable, boolean isJsonBodyRequired, Request httpRequest) { - return handleRequest(operation, null, null, pathId, pathVariable, isJsonBodyRequired, httpRequest); + String operation, + String pathId, + String pathVariable, + boolean isJsonBodyRequired, + Request httpRequest) { + return handleRequest( + operation, null, null, pathId, pathVariable, isJsonBodyRequired, httpRequest); } protected CompletionStage handleRequest( - String operation, - JsonNode requestBodyJson, - Function requestValidatorFn, - Map headers, Request httpRequest) { - return handleRequest(operation, requestBodyJson, requestValidatorFn, null, null, headers, true, httpRequest); + String operation, + JsonNode requestBodyJson, + Function requestValidatorFn, + Map headers, + Request httpRequest) { + return handleRequest( + operation, requestBodyJson, requestValidatorFn, null, null, headers, true, httpRequest); } protected CompletionStage handleRequest( - String operation, - Function requestValidatorFn, - String pathId, - String pathVariable, Request httpRequest) { - return handleRequest(operation, null, requestValidatorFn, pathId, pathVariable, false, httpRequest); + String operation, + Function requestValidatorFn, + String pathId, + String pathVariable, + Request httpRequest) { + return handleRequest( + operation, null, requestValidatorFn, pathId, pathVariable, false, httpRequest); } protected CompletionStage handleRequest( - String operation, - JsonNode requestBodyJson, - Function requestValidatorFn, - String pathId, - String pathVariable, Request httpRequest) { + String operation, + JsonNode requestBodyJson, + Function requestValidatorFn, + String pathId, + String pathVariable, + Request httpRequest) { return handleRequest( operation, requestBodyJson, requestValidatorFn, pathId, pathVariable, true, httpRequest); } @@ -174,17 +192,18 @@ protected CompletionStage handleRequest( pathVariable, null, isJsonBodyRequired, - httpRequest); + httpRequest); } protected CompletionStage handleRequest( - String operation, - JsonNode requestBodyJson, - Function requestValidatorFn, - String pathId, - String pathVariable, - Map headers, - boolean isJsonBodyRequired, Request httpRequest) { + String operation, + JsonNode requestBodyJson, + Function requestValidatorFn, + String pathId, + String pathVariable, + Map headers, + boolean isJsonBodyRequired, + Request httpRequest) { try { org.sunbird.common.request.Request request = null; if (!isJsonBodyRequired) { @@ -199,23 +218,33 @@ protected CompletionStage handleRequest( if (requestValidatorFn != null) requestValidatorFn.apply(request); if (headers != null) request.getContext().put(JsonKey.HEADER, headers); + ProjectLogger.log( + "BaseController:handleRequest for operation: " + + operation + + " requestId: " + + request.getRequestId(), + LoggerEnum.INFO.name()); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { ProjectLogger.log( - "BaseController:handleRequest: Exception occurred with error message = " + e.getMessage(), + "BaseController:handleRequest for operation: " + + operation + + " Exception occurred with error message = " + + e.getMessage(), e); return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); } } protected CompletionStage handleSearchRequest( - String operation, - JsonNode requestBodyJson, - Function requestValidatorFn, - String pathId, - String pathVariable, - Map headers, - String esObjectType, Request httpRequest) { + String operation, + JsonNode requestBodyJson, + Function requestValidatorFn, + String pathId, + String pathVariable, + Map headers, + String esObjectType, + Request httpRequest) { try { org.sunbird.common.request.Request request = null; if (null != requestBodyJson) { @@ -327,7 +356,7 @@ public static Result createSuccessResponse(Request request, Response response) { } return Results.ok(Json.toJson(response)) - .withHeader(HeaderParam.X_Response_Length.getName(), value); + .withHeader(HeaderParam.X_Response_Length.getName(), value); } /** @@ -423,32 +452,33 @@ public Result createCommonResponse(Object response, String key, Request request) params.put(JsonKey.DURATION, calculateApiTimeTaken(startTime)); removeFields(params, JsonKey.START_TIME); params.put( - JsonKey.STATUS, String.valueOf(((Response) response).getResponseCode().getResponseCode())); + JsonKey.STATUS, + String.valueOf(((Response) response).getResponseCode().getResponseCode())); params.put(JsonKey.LOG_LEVEL, JsonKey.INFO); req.setRequest( - generateTelemetryRequestForController( - TelemetryEvents.LOG.getName(), - params, - (Map) requestInfo.get(JsonKey.CONTEXT))); + generateTelemetryRequestForController( + TelemetryEvents.LOG.getName(), + params, + (Map) requestInfo.get(JsonKey.CONTEXT))); // if any request is coming form /v1/telemetry/save then don't generate the telemetry log // for it. lmaxWriter.submitMessage(req); } catch (Exception ex) { ProjectLogger.log( - "BaseController:createCommonResponse Exception in writing telemetry for request " - + requestId, - ex); + "BaseController:createCommonResponse Exception in writing telemetry for request " + + requestId, + ex); } finally { // remove request info from map OnRequestHandler.requestInfo.remove(requestId); ProjectLogger.log( - "BaseController:createCommonResponse removed details for messageId=" + requestId, - LoggerEnum.INFO); + "BaseController:createCommonResponse removed details for messageId=" + requestId, + LoggerEnum.INFO); } } else { ProjectLogger.log( - "BaseController:createCommonResponse request details not found requestId=" + requestId, - LoggerEnum.ERROR); + "BaseController:createCommonResponse request details not found requestId=" + requestId, + LoggerEnum.ERROR); } Response courseResponse = (Response) response; if (!StringUtils.isBlank(key)) { @@ -465,8 +495,8 @@ public Result createCommonResponse(Object response, String key, Request request) */ public Result createFileDownloadResponse(File file) { return Results.ok(file) - .withHeader("Content-Type", "application/x-download") - .withHeader("Content-disposition", "attachment; filename=" + file.getName()); + .withHeader("Content-Type", "application/x-download") + .withHeader("Content-disposition", "attachment; filename=" + file.getName()); } private void removeFields(Map params, String... properties) { @@ -515,35 +545,40 @@ public Result createCommonExceptionResponse(Exception e, Request request) { ResponseCode.internalError.getErrorMessage(), ResponseCode.SERVER_ERROR.getResponseCode()); } - try { - Map requestInfo = OnRequestHandler.requestInfo.get(request.flash().get(JsonKey.REQUEST_ID)); - org.sunbird.common.request.Request reqForTelemetry = new org.sunbird.common.request.Request(); - Map params = (Map) requestInfo.get(JsonKey.ADDITIONAL_INFO); - params.put(JsonKey.LOG_TYPE, JsonKey.API_ACCESS); - params.put(JsonKey.MESSAGE, ""); - params.put(JsonKey.METHOD, request.method()); - // calculate the total time consume - long startTime = (Long) params.get(JsonKey.START_TIME); - params.put(JsonKey.DURATION, calculateApiTimeTaken(startTime)); - removeFields(params, JsonKey.START_TIME); - params.put(JsonKey.STATUS, String.valueOf(exception.getResponseCode())); - params.put(JsonKey.LOG_LEVEL, "error"); - params.put(JsonKey.STACKTRACE, generateStackTrace(exception.getStackTrace())); - reqForTelemetry.setRequest( - generateTelemetryRequestForController( - TelemetryEvents.ERROR.getName(), - params, - (Map) requestInfo.get(JsonKey.CONTEXT))); - lmaxWriter.submitMessage(reqForTelemetry); - } catch (Exception ex) { - ex.printStackTrace(); - } + generateExceptionTelemetry(request, exception); // cleaning request info ... return Results.status( exception.getResponseCode(), Json.toJson(BaseController.createResponseOnException(req, exception))); } + private void generateExceptionTelemetry(Request request, ProjectCommonException exception) { + try { + Map requestInfo = + OnRequestHandler.requestInfo.get(request.flash().get(JsonKey.REQUEST_ID)); + org.sunbird.common.request.Request reqForTelemetry = new org.sunbird.common.request.Request(); + Map params = (Map) requestInfo.get(JsonKey.ADDITIONAL_INFO); + params.put(JsonKey.LOG_TYPE, JsonKey.API_ACCESS); + params.put(JsonKey.MESSAGE, ""); + params.put(JsonKey.METHOD, request.method()); + // calculate the total time consume + long startTime = (Long) params.get(JsonKey.START_TIME); + params.put(JsonKey.DURATION, calculateApiTimeTaken(startTime)); + removeFields(params, JsonKey.START_TIME); + params.put(JsonKey.STATUS, String.valueOf(exception.getResponseCode())); + params.put(JsonKey.LOG_LEVEL, "error"); + params.put(JsonKey.STACKTRACE, generateStackTrace(exception.getStackTrace())); + reqForTelemetry.setRequest( + generateTelemetryRequestForController( + TelemetryEvents.ERROR.getName(), + params, + (Map) requestInfo.get(JsonKey.CONTEXT))); + lmaxWriter.submitMessage(reqForTelemetry); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + private long calculateApiTimeTaken(Long startTime) { Long timeConsumed = null; @@ -569,24 +604,21 @@ public CompletionStage actorResponseHandler( Timeout timeout, String responseKey, Request httpReq) { - - String operation = request.getOperation(); - - // set header to request object , setting actor type and channel headers value - // ... setChannelAndActorInfo(httpReq, request); - Function function = - new Function() { - @Override - public Result apply(Object result) { - if (ActorOperations.HEALTH_CHECK.getValue().equals(request.getOperation())) { - setGlobalHealthFlag(result); - } + result -> { + if (ActorOperations.HEALTH_CHECK.getValue().equals(request.getOperation())) { + setGlobalHealthFlag(result); + } - if (result instanceof Response) { - Response response = (Response) result; + if (result instanceof Response) { + Response response = (Response) result; + if (ResponseCode.OK.getResponseCode() + == (response.getResponseCode().getResponseCode())) { return createCommonResponse(response, responseKey, httpReq); + } else if (ResponseCode.CLIENT_ERROR.getResponseCode() + == (response.getResponseCode().getResponseCode())) { + return createClientErrorResponse(httpReq, (ClientErrorResponse) response); } else if (result instanceof ProjectCommonException) { return createCommonExceptionResponse((ProjectCommonException) result, httpReq); } else if (result instanceof File) { @@ -594,6 +626,12 @@ public Result apply(Object result) { } else { return createCommonExceptionResponse(new Exception(), httpReq); } + } else if (result instanceof ProjectCommonException) { + return createCommonExceptionResponse((ProjectCommonException) result, httpReq); + } else if (result instanceof File) { + return createFileDownloadResponse((File) result); + } else { + return createCommonExceptionResponse(new Exception(), httpReq); } }; @@ -604,6 +642,15 @@ public Result apply(Object result) { } } + private Result createClientErrorResponse(Request httpReq, ClientErrorResponse response) { + ClientErrorResponse errorResponse = response; + generateExceptionTelemetry(httpReq, errorResponse.getException()); + Response responseObj = + BaseController.createResponseOnException(httpReq, errorResponse.getException()); + responseObj.getResult().putAll(errorResponse.getResult()); + return Results.status(errorResponse.getException().getResponseCode(), Json.toJson(responseObj)); + } + /** * This method will provide environment id. * @@ -678,9 +725,9 @@ public static String getResponseId(String requestPath) { String requestUrl = (path.split("\\?"))[0]; if (requestUrl.contains(ver)) { requestUrl = requestUrl.replaceFirst(ver, "api"); - } else if (requestUrl.contains(ver2) ) { + } else if (requestUrl.contains(ver2)) { requestUrl = requestUrl.replaceFirst(ver2, "api"); - } else if (requestUrl.contains(ver3) ) { + } else if (requestUrl.contains(ver3)) { requestUrl = requestUrl.replaceFirst(ver3, "api"); } String[] list = requestUrl.split("/"); @@ -744,10 +791,11 @@ public static void setActorRef(Object obj) { private static Map genarateTelemetryInfoForError(Request request) { Map map = new HashMap<>(); - Map requestInfo = OnRequestHandler.requestInfo.get(request.flash().get(JsonKey.REQUEST_ID)); - if(requestInfo != null) { - Map contextInfo = (Map) requestInfo.get(JsonKey.CONTEXT); - map.put(JsonKey.CONTEXT, contextInfo); + Map requestInfo = + OnRequestHandler.requestInfo.get(request.flash().get(JsonKey.REQUEST_ID)); + if (requestInfo != null) { + Map contextInfo = (Map) requestInfo.get(JsonKey.CONTEXT); + map.put(JsonKey.CONTEXT, contextInfo); } Map params = new HashMap<>(); params.put(JsonKey.ERR_TYPE, JsonKey.API_ACCESS); @@ -755,10 +803,11 @@ private static Map genarateTelemetryInfoForError(Request request return map; } - public void setChannelAndActorInfo(Http.Request httpReq, org.sunbird.common.request.Request reqObj) { + public void setChannelAndActorInfo( + Http.Request httpReq, org.sunbird.common.request.Request reqObj) { reqObj.getContext().put(JsonKey.CHANNEL, httpReq.flash().get(JsonKey.CHANNEL)); - reqObj.getContext().put(JsonKey.ACTOR_ID,httpReq.flash().get(JsonKey.ACTOR_ID)); + reqObj.getContext().put(JsonKey.ACTOR_ID, httpReq.flash().get(JsonKey.ACTOR_ID)); reqObj.getContext().put(JsonKey.ACTOR_TYPE, httpReq.flash().get(JsonKey.ACTOR_TYPE)); reqObj.getContext().put(JsonKey.APP_ID, httpReq.flash().get(JsonKey.APP_ID)); reqObj.getContext().put(JsonKey.DEVICE_ID, httpReq.flash().get(JsonKey.DEVICE_ID)); @@ -766,12 +815,12 @@ public void setChannelAndActorInfo(Http.Request httpReq, org.sunbird.common.requ .getContext() .put( JsonKey.SIGNUP_TYPE, - httpReq.flash().get(JsonKey.SIGNUP_TYPE)); // adding signup type in request context + httpReq.flash().get(JsonKey.SIGNUP_TYPE)); // adding signup type in request context reqObj .getContext() .put( JsonKey.REQUEST_SOURCE, - httpReq.flash().get(JsonKey.REQUEST_SOURCE)); // ADDING Source under params in context + httpReq.flash().get(JsonKey.REQUEST_SOURCE)); // ADDING Source under params in context httpReq.flash().remove(JsonKey.APP_ID); } @@ -825,7 +874,8 @@ private void setGlobalHealthFlag(Object result) { OnRequestHandler.isServiceHealthy = false; } ProjectLogger.log( - "BaseController:setGlobalHealthFlag: isServiceHealthy = " + OnRequestHandler.isServiceHealthy, + "BaseController:setGlobalHealthFlag: isServiceHealthy = " + + OnRequestHandler.isServiceHealthy, LoggerEnum.INFO.name()); } diff --git a/service/app/controllers/healthmanager/HealthController.java b/service/app/controllers/healthmanager/HealthController.java index b9640c716e..836b1eab6e 100644 --- a/service/app/controllers/healthmanager/HealthController.java +++ b/service/app/controllers/healthmanager/HealthController.java @@ -8,7 +8,10 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import javax.inject.Inject; +import modules.SignalHandler; import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.response.Response; import org.sunbird.common.models.util.ActorOperations; import org.sunbird.common.models.util.HttpUtil; @@ -19,12 +22,14 @@ import org.sunbird.common.models.util.PropertiesCache; import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; import play.mvc.Http; import play.mvc.Result; /** @author Manzarul */ public class HealthController extends BaseController { private static List list = new ArrayList<>(); + @Inject SignalHandler signalHandler; static { list.add("service"); @@ -41,6 +46,7 @@ public class HealthController extends BaseController { */ public CompletionStage getHealth(Http.Request httpRequest) { try { + handleSigTerm(); Request reqObj = new Request(); reqObj.setOperation(ActorOperations.HEALTH_CHECK.getValue()); reqObj.setRequestId(ExecutionContext.getRequestId()); @@ -66,6 +72,7 @@ public CompletionStage getLearnerServiceHealth(String val, Http.Request return getEkStepHealtCheck(httpRequest); } else { try { + handleSigTerm(); Request reqObj = new Request(); reqObj.setOperation(val); reqObj.setRequestId(ExecutionContext.getRequestId()); @@ -77,16 +84,35 @@ public CompletionStage getLearnerServiceHealth(String val, Http.Request } } } else { - responseList.add(ProjectUtil.createCheckResponse(JsonKey.LEARNER_SERVICE, false, null)); - finalResponseMap.put(JsonKey.CHECKS, responseList); - finalResponseMap.put(JsonKey.NAME, "Learner service health"); - finalResponseMap.put(JsonKey.Healthy, true); - Response response = new Response(); - response.getResult().put(JsonKey.RESPONSE, finalResponseMap); - response.setId("learner.service.health.api"); - response.setVer(getApiVersion(httpRequest.path())); - response.setTs(ExecutionContext.getRequestId()); - return CompletableFuture.completedFuture(ok(play.libs.Json.toJson(response))); + try { + handleSigTerm(); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.LEARNER_SERVICE, false, null)); + finalResponseMap.put(JsonKey.CHECKS, responseList); + finalResponseMap.put(JsonKey.NAME, "Learner service health"); + finalResponseMap.put(JsonKey.Healthy, true); + Response response = new Response(); + response.getResult().put(JsonKey.RESPONSE, finalResponseMap); + response.setId("learner.service.health.api"); + response.setVer(getApiVersion(httpRequest.path())); + response.setTs(ExecutionContext.getRequestId()); + return CompletableFuture.completedFuture(ok(play.libs.Json.toJson(response))); + } catch (Exception e) { + return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); + } + } + } + + private void handleSigTerm() { + if (signalHandler.isShuttingDown()) { + ProjectLogger.log( + "SIGTERM is " + + signalHandler.isShuttingDown() + + ", So play server will not allow any new request.", + LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.serviceUnAvailable.getErrorCode(), + ResponseCode.serviceUnAvailable.getErrorMessage(), + ResponseCode.SERVICE_UNAVAILABLE.getResponseCode()); } } @@ -131,4 +157,5 @@ public CompletionStage getEkStepHealtCheck(play.mvc.Http.Request request response.setTs(ExecutionContext.getRequestId()); return CompletableFuture.completedFuture(ok(play.libs.Json.toJson(response))); } + } diff --git a/service/app/modules/SignalHandler.java b/service/app/modules/SignalHandler.java new file mode 100644 index 0000000000..7c428217a7 --- /dev/null +++ b/service/app/modules/SignalHandler.java @@ -0,0 +1,48 @@ +package modules; + +import akka.actor.ActorSystem; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import play.api.Application; +import play.api.Play; +import scala.concurrent.duration.Duration; +import scala.concurrent.duration.FiniteDuration; +import sun.misc.Signal; + +@Singleton +public class SignalHandler { + + private static long stopDelay = Long.parseLong(ProjectUtil.getConfigValue("sigterm_stop_delay")); + private static final FiniteDuration STOP_DELAY = Duration.create(stopDelay, TimeUnit.SECONDS); + + private volatile boolean isShuttingDown = false; + + @Inject + public SignalHandler(ActorSystem actorSystem, Provider applicationProvider) { + Signal.handle( + new Signal("TERM"), + signal -> { + isShuttingDown = true; + ProjectLogger.log( + "Termination required, swallowing SIGTERM to allow current requests to finish", + LoggerEnum.INFO.name()); + actorSystem + .scheduler() + .scheduleOnce( + STOP_DELAY, + () -> { + Play.stop(applicationProvider.get()); + }, + actorSystem.dispatcher()); + }); + } + + public boolean isShuttingDown() { + return isShuttingDown; + } +} diff --git a/service/app/modules/StartModule.java b/service/app/modules/StartModule.java index 1a05e8fadc..e0bc4091fe 100644 --- a/service/app/modules/StartModule.java +++ b/service/app/modules/StartModule.java @@ -11,6 +11,7 @@ protected void configure() { System.out.println("StartModule:configure: Start"); ProjectLogger.log("StartModule:configure: Start", LoggerEnum.INFO.name()); try { + bind(SignalHandler.class).asEagerSingleton(); bind(ApplicationStart.class).asEagerSingleton(); } catch (Exception | Error e) { e.printStackTrace(); diff --git a/service/pom.xml b/service/pom.xml index 72d0361a84..cf22afa764 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -55,11 +55,6 @@ mw-service 1.0-SNAPSHOT - - com.typesafe - config - 1.3.0 - com.typesafe.play play_${scala.major.version} @@ -91,53 +86,6 @@ - - org.scala-lang - scala-library - ${scala.version} - - - - org.apache.httpcomponents - httpclient - 4.5.1 - - - - com.typesafe.akka - akka-slf4j_${scala.major.version} - ${learner.akka.version} - - - com.typesafe.akka - akka-testkit_${scala.major.version} - ${learner.akka.version} - test - - - org.powermock - powermock-module-junit4 - 1.6.5 - test - - - junit - junit - - - - - org.powermock - powermock-api-mockito - 1.6.5 - test - - - junit - junit - 4.12 - test - com.typesafe.play filters-helpers_${scala.major.version} diff --git a/setupRepo.sh b/setupRepo.sh new file mode 100644 index 0000000000..e69de29bb2