diff --git a/docs/Running.adoc b/docs/Running.adoc index b0b9dba..43baf9c 100644 --- a/docs/Running.adoc +++ b/docs/Running.adoc @@ -36,6 +36,11 @@ image::../assets/monitor.png[Monitor Jobs] See link:Monitoring.adoc[Monitoring / Validating the Content Sync] for information on evaluating the returned information. +=== Stopping a Job + +From the main screen, enter "s" to stop an existing job. You will be prompted to enter job id. + +Enter the job id that you wish to terminate. That job will then be stopped. ==== Configuration diff --git a/grabbit.sh b/grabbit.sh index d13851a..23eece3 100755 --- a/grabbit.sh +++ b/grabbit.sh @@ -88,6 +88,20 @@ function monitorStatus { done } +function stopJob { + echo "Enter jobID to stop, or \"b\" to go back" + read selection + if [ "$selection" == "b" ]; then + echo "*****************************************************" + return + fi + statusJson=`curl -s -u $username:$password --request DELETE $client$GRABBIT_JOB"?jobId="$selection` + echo + echo "$statusJson" + echo "*****************************************************" +} + + clear echo $SET_BLUE echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" @@ -105,12 +119,14 @@ echo "Client Password :" read -s password while true; do - echo "Enter \"n\" for new job request, \"m\" to monitor, or \"q\" to quit" + echo "Enter \"n\" for new job request, \"m\" to monitor, \"s\" to stop a job, or \"q\" to quit" read selection if [ "$selection" == "n" ]; then newGrabbitRequest elif [ "$selection" == "m" ]; then monitorStatus + elif [ "$selection" == "s" ]; then + stopJob elif [ "$selection" == "q" ]; then exit 0; else diff --git a/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy b/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy index eb71470..aec8892 100644 --- a/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy +++ b/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy @@ -32,10 +32,10 @@ import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.apache.sling.api.servlets.SlingAllMethodsServlet import org.springframework.batch.core.explore.JobExplorer +import org.springframework.batch.core.launch.support.SimpleJobOperator import org.springframework.context.ConfigurableApplicationContext -import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST -import static javax.servlet.http.HttpServletResponse.SC_OK +import static javax.servlet.http.HttpServletResponse.* /** * This servlet is used to manage Grabbit jobs. @@ -49,7 +49,7 @@ import static javax.servlet.http.HttpServletResponse.SC_OK */ @Slf4j @CompileStatic -@SlingServlet(methods = ['GET', 'PUT'], resourceTypes = ['twcable:grabbit/job']) +@SlingServlet(methods = ['GET', 'PUT', 'DELETE'], resourceTypes = ['twcable:grabbit/job']) class GrabbitJobServlet extends SlingAllMethodsServlet { //A "special" meta-jobID that allows for the status of all jobs to be queried. @@ -147,6 +147,34 @@ class GrabbitJobServlet extends SlingAllMethodsServlet { response.writer.write(new JsonBuilder(jobExecutionIds).toString()) } + @Override + protected void doDelete(SlingHttpServletRequest request, SlingHttpServletResponse response) { + String jobExecutionId = request.getParameter("jobId") ?: "" + + if(jobExecutionId == ALL_JOBS_ID) { + response.setStatus(SC_BAD_REQUEST) + response.writer.write("Stopping 'all' jobs is not supported. Please specify single job id") + return + } + if(!jobExecutionId.isLong()) { + log.warn "Parameter ${jobExecutionId} 'jobId' is invalid" + response.status = SC_BAD_REQUEST + response.writer.write("Parameter 'jobId' is invalid") + return + } + try { + SimpleJobOperator jobOperator = configurableApplicationContext.getBean(SimpleJobOperator) + jobOperator.stop(jobExecutionId.toLong()) + response.status = SC_OK + response.writer.write("Job ${jobExecutionId} Successfully Stopped") + } + catch (Exception exception){ + response.status = SC_NOT_FOUND + response.writer.write("Could not find a running job with id ${jobExecutionId}") + } + + } + /** * Will return the status of a job from the {@link org.springframework.batch.core.explore.JobExplorer} used in JSON format. * @param jobId The jobID to get status. diff --git a/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy b/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy index 86dc95d..f8a8e8e 100644 --- a/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy +++ b/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy @@ -27,6 +27,9 @@ import org.apache.sling.api.resource.Resource import org.apache.sling.api.resource.ResourceMetadata import org.springframework.batch.core.JobParameters import org.springframework.batch.core.explore.JobExplorer +import org.springframework.batch.core.launch.JobExecutionNotRunningException +import org.springframework.batch.core.launch.NoSuchJobException +import org.springframework.batch.core.launch.support.SimpleJobOperator import org.springframework.context.ConfigurableApplicationContext import spock.lang.Specification import spock.lang.Subject @@ -36,8 +39,7 @@ import javax.annotation.Nonnull import javax.servlet.ServletInputStream import static com.twcable.grabbit.client.servlets.GrabbitJobServlet.ALL_JOBS_ID -import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST -import static javax.servlet.http.HttpServletResponse.SC_OK +import static javax.servlet.http.HttpServletResponse.* @Subject(GrabbitJobServlet) class GrabbitJobServletSpec extends Specification { @@ -234,6 +236,39 @@ class GrabbitJobServletSpec extends Specification { //One causes SnakeYAML to produce a null config map, and the other does not pass our validations (missing values) } + def "Stop job response check with differnt set of jobId parameter"() { + given: + SlingHttpServletRequest request = Mock(SlingHttpServletRequest) { + getParameter("jobId") >> inputJobId + } + SlingHttpServletResponse response = Mock(SlingHttpServletResponse) { + getWriter() >> Mock(PrintWriter) + } + GrabbitJobServlet servlet = new GrabbitJobServlet() + final applicationContext = Mock(ConfigurableApplicationContext) { + getBean(SimpleJobOperator) >> Mock(SimpleJobOperator) { + stop(123L) >> true + stop(222L) >> {throw new NoSuchJobException("Job does not exist")} + stop(333L) >> {throw new JobExecutionNotRunningException("Job not running")} + } + } + servlet.setConfigurableApplicationContext(applicationContext) + + when: + servlet.doDelete(request, response) + + then: + 1 * response.setStatus(expectedResponse) + + where: + inputJobId | expectedResponse + 123L | SC_OK + 222L | SC_NOT_FOUND + 333L | SC_NOT_FOUND + "aaa" | SC_BAD_REQUEST + "" | SC_BAD_REQUEST + } + class StubServletInputStream extends ServletInputStream {