package eu.openaire.urls_controller.controllers; import eu.openaire.urls_controller.models.WorkerInfo; import eu.openaire.urls_controller.services.ShutdownService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController @RequestMapping("") public class ShutdownController { private static final Logger logger = LoggerFactory.getLogger(ShutdownController.class); @Autowired ShutdownService shutdownService; public static boolean shouldShutdownService = false; @PostMapping("shutdownService") public ResponseEntity shutdownServiceGracefully(HttpServletRequest request) { String initMsg = "Received a \"shutdownService\" request. "; ResponseEntity responseEntity = shutdownService.passSecurityChecks(request, initMsg); if ( responseEntity != null ) return responseEntity; String finalMsg = ""; if ( shouldShutdownService ) finalMsg = "The controller has already received a \"shutdownService\" (which was not canceled afterwards)."; else { shouldShutdownService = true; // Send "shutdownWorker" requests to all Workers. for ( String workerId : UrlsController.workersInfoMap.keySet() ) shutdownService.postShutdownOrCancelRequestToWorker(workerId, UrlsController.workersInfoMap.get(workerId).getWorkerIP(), false); // That's it for now. The workers may take some hours to finish their work (including delivering the full-text files). // TODO - Add a scheduler to monitor the "HasShutdown" values for all workers. // TODO - Once all have the value "true", gently shutdown the Controller, just like we do for the worker. // TODO - Each worker, upon "shutdown" should send a "workerShutdownReport" to the Controller. } finalMsg += "The service will shutdown, after finishing current work."; logger.info(initMsg + finalMsg); return ResponseEntity.ok().body(finalMsg + "\n"); } @PostMapping("cancelShutdownService") public ResponseEntity cancelShutdownServiceGracefully(HttpServletRequest request) { String initMsg = "Received a \"cancelShutdownService\" request. "; ResponseEntity responseEntity = shutdownService.passSecurityChecks(request, initMsg); if ( responseEntity != null ) return responseEntity; shouldShutdownService = false; // Send "cancelShutdownWorker" requests to all Workers. for ( String workerId : UrlsController.workersInfoMap.keySet() ) shutdownService.postShutdownOrCancelRequestToWorker(workerId, UrlsController.workersInfoMap.get(workerId).getWorkerIP(), true); String finalMsg = "Any previous \"shutdownService\"-request is canceled."; logger.info(initMsg + finalMsg); return ResponseEntity.ok().body(finalMsg + "\n"); } @PostMapping("workerShutdownReport") public ResponseEntity workerShutdownReport(@RequestParam String workerId, HttpServletRequest request) { String initMsg = "Received a \"workerShutdownReport\" from worker: \"" + workerId + "\"."; WorkerInfo workerInfo = UrlsController.workersInfoMap.get(workerId); if ( workerInfo == null ) { String errorMsg = "The worker with id \"" + workerId + "\" has not participated in the PDF-Aggregation-Service"; logger.warn(initMsg + "\n" + errorMsg); return ResponseEntity.badRequest().body(errorMsg); } String remoteAddr = request.getHeader("X-FORWARDED-FOR"); if ( remoteAddr == null || remoteAddr.isEmpty() ) remoteAddr = request.getRemoteAddr(); if ( ! remoteAddr.equals(workerInfo.getWorkerIP()) ) { logger.error(initMsg + " The request came from another IP: " + remoteAddr + " | while this worker was registered with the IP: " + workerInfo.getWorkerIP()); return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } logger.info(initMsg); workerInfo.setHasShutdown(true); // This will update the map. // Return "HTTP-OK" to this worker and wait for the scheduler to check and shutdown the service. return ResponseEntity.ok().build(); } }