Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 78085ce

Browse files
author
Corneil du Plessis
authored
Add task thin executions by name and fix missing docs. (#5994)
* Change TaskTemplate to use task/thinexecutions instead of task/executions. Add task thin executions by name. Update api-guide.adoc with links to generated documentation. Modify TaskCommands to use thin executions since it provides the data required. Removed duplicate entries from api docs. Fixes #5991 Fixes #5973 * Fix root controller expected response with thinexecutions/name. * Add rest docs generation with full profile to CI PR. * Added a test for invalid name returning empty page on thinexecutions. Fixes #5989 * Updated thin taskexecutions by name to return 404 when definition is not found. Provide task/execution and thin executions by name test when task is not defined and where it is defined. Removed excess `andDo(print())` from tests. * Fix test with added definition for covering all tasks/executions and tasks/thinexecutions name search scenarios. * Revert CI-PR.
1 parent b27f0c2 commit 78085ce

File tree

19 files changed

+242
-42
lines changed

19 files changed

+242
-42
lines changed

spring-cloud-dataflow-classic-docs/src/test/java/org/springframework/cloud/dataflow/server/rest/documentation/ApiDocumentation.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,14 @@ void index() throws Exception {
115115
linkWithRel("tasks/executions/external").description("Returns Task execution by external id"),
116116
linkWithRel("tasks/executions/current").description("Provides the current count of running tasks"),
117117
linkWithRel("tasks/thinexecutions").description("Returns thin Task executions"),
118+
linkWithRel("tasks/thinexecutions/name").description("Returns thin Task executions for a given task name"),
118119
linkWithRel("tasks/info/executions").description("Provides the task executions info"),
119120
linkWithRel("tasks/schedules").description("Provides schedule information of tasks"),
120121
linkWithRel("tasks/schedules/instances").description("Provides schedule information of a specific task "),
121122
linkWithRel("tasks/executions/name").description("Returns all task executions for a given Task name"),
122123
linkWithRel("tasks/executions/execution").description("Provides details for a specific task execution"),
123124
linkWithRel("tasks/platforms").description("Provides platform accounts for launching tasks. The results can be filtered to show the platforms that support scheduling by adding a request parameter of 'schedulesEnabled=true"),
124125
linkWithRel("tasks/logs").description("Retrieve the task application log"),
125-
linkWithRel("tasks/thinexecutions").description("Returns thin Task executions"),
126126

127127
linkWithRel("streams/definitions").description("Exposes the Streams resource"),
128128
linkWithRel("streams/definitions/definition").description("Handle a specific Stream definition"),
@@ -221,14 +221,15 @@ void index() throws Exception {
221221

222222
fieldWithPath("_links.tasks/thinexecutions.href").description("Link to the tasks/thinexecutions"),
223223

224+
fieldWithPath("_links.tasks/thinexecutions/name.href").description("Link to the tasks/thinexecutions/name"),
225+
fieldWithPath("_links.tasks/thinexecutions/name.templated").description("Link to the tasks/thinexecutions/name is templated"),
226+
224227
fieldWithPath("_links.tasks/info/executions.href").description("Link to the tasks/info/executions"),
225228
fieldWithPath("_links.tasks/info/executions.templated").type(JsonFieldType.BOOLEAN).optional().description("Link tasks/info is templated"),
226229

227230
fieldWithPath("_links.tasks/logs.href").description("Link to the tasks/logs"),
228231
fieldWithPath("_links.tasks/logs.templated").type(JsonFieldType.BOOLEAN).optional().description("Link tasks/logs is templated"),
229232

230-
fieldWithPath("_links.tasks/thinexecutions.href").description("Link to the tasks/thinexecutions"),
231-
232233
fieldWithPath("_links.tasks/schedules.href").description("Link to the tasks/executions/schedules"),
233234
fieldWithPath("_links.tasks/schedules/instances.href").description("Link to the tasks/schedules/instances"),
234235
fieldWithPath("_links.tasks/schedules/instances.templated").type(JsonFieldType.BOOLEAN).optional().description("Link tasks/schedules/instances is templated"),

spring-cloud-dataflow-classic-docs/src/test/java/org/springframework/cloud/dataflow/server/rest/documentation/TaskExecutionsDocumentation.java

+26-4
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,9 @@ void listTaskThinExecutions() throws Exception {
312312
}
313313

314314
@Test
315-
void listTaskExecutionsByName() throws Exception {
315+
void listTaskThinExecutionsByName() throws Exception {
316316
this.mockMvc.perform(
317-
get("/tasks/executions")
317+
get("/tasks/thinexecutions")
318318
.queryParam("name", "taskB")
319319
.queryParam("page", "0")
320320
.queryParam("size", "10")
@@ -328,11 +328,33 @@ void listTaskExecutionsByName() throws Exception {
328328
parameterWithName("name")
329329
.description("The name associated with the task execution")),
330330
responseFields(
331-
subsectionWithPath("_embedded.taskExecutionResourceList")
332-
.description("Contains a collection of Task Executions/"),
331+
subsectionWithPath("_embedded.taskExecutionThinResourceList")
332+
.description("Contains a collection of thin Task Executions/"),
333333
subsectionWithPath("_links.self").description("Link to the task execution resource"),
334334
subsectionWithPath("page").description("Pagination properties"))));
335335
}
336+
@Test
337+
void listTaskExecutionsByName() throws Exception {
338+
this.mockMvc.perform(
339+
get("/tasks/executions")
340+
.queryParam("name", "taskB")
341+
.queryParam("page", "0")
342+
.queryParam("size", "10")
343+
)
344+
.andExpect(status().isOk()).andDo(this.documentationHandler.document(
345+
queryParameters(
346+
parameterWithName("page")
347+
.description("The zero-based page number (optional)"),
348+
parameterWithName("size")
349+
.description("The requested page size (optional)"),
350+
parameterWithName("name")
351+
.description("The name associated with the task execution")),
352+
responseFields(
353+
subsectionWithPath("_embedded.taskExecutionResourceList")
354+
.description("Contains a collection of Task Executions/"),
355+
subsectionWithPath("_links.self").description("Link to the task execution resource"),
356+
subsectionWithPath("page").description("Pagination properties"))));
357+
}
336358

337359
@Test
338360
void stopTask() throws Exception {

spring-cloud-dataflow-docs/src/main/asciidoc/api-guide.adoc

+79
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,85 @@ include::{snippets}/task-executions-documentation/list-task-executions-by-name/c
20672067
include::{snippets}/task-executions-documentation/list-task-executions-by-name/http-response.adoc[]
20682068

20692069

2070+
[[api-guide-resources-task-thin-executions-list]]
2071+
==== List All Task Thin Executions
2072+
2073+
The task executions endpoint lets you list all task executions with only top-level data.
2074+
The following topics provide more details:
2075+
2076+
* <<api-guide-resources-task-thin-executions-list-request-structure>>
2077+
* <<api-guide-resources-task-thin-executions-list-request-parameters>>
2078+
* <<api-guide-resources-task-thin-executions-list-example-request>>
2079+
* <<api-guide-resources-task-thin-executions-list-response-structure>>
2080+
2081+
2082+
2083+
[[api-guide-resources-task-thin-executions-list-request-structure]]
2084+
===== Request Structure
2085+
2086+
include::{snippets}/task-executions-documentation/list-task-thin-executions/http-request.adoc[]
2087+
2088+
2089+
2090+
[[api-guide-resources-task-thin-executions-list-request-parameters]]
2091+
===== Request Parameters
2092+
2093+
include::{snippets}/task-executions-documentation/list-task-thin-executions/request-parameters.adoc[]
2094+
2095+
2096+
2097+
[[api-guide-resources-task-thin-executions-list-example-request]]
2098+
===== Example Request
2099+
2100+
include::{snippets}/task-executions-documentation/list-task-thin-executions/curl-request.adoc[]
2101+
2102+
2103+
2104+
[[api-guide-resources-task-thin-executions-list-response-structure]]
2105+
===== Response Structure
2106+
2107+
include::{snippets}/task-executions-documentation/list-task-thin-executions/http-response.adoc[]
2108+
2109+
2110+
2111+
[[api-guide-resources-task-thin-executions-list-by-name]]
2112+
==== List All Task Thin Executions With a Specified Task Name
2113+
2114+
The task thin executions endpoint lets you list task executions with a specified task name.
2115+
The following topics provide more details:
2116+
2117+
* <<api-guide-resources-task-thin-executions-list-by-name-request-structure>>
2118+
* <<api-guide-resources-task-thin-executions-list-by-name-request-parameters>>
2119+
* <<api-guide-resources-task-thin-executions-list-by-name-example-request>>
2120+
* <<api-guide-resources-task-thin-executions-list-by-name-response-structure>>
2121+
2122+
2123+
2124+
[[api-guide-resources-task-thin-executions-list-by-name-request-structure]]
2125+
===== Request Structure
2126+
2127+
include::{snippets}/task-executions-documentation/list-task-thin-executions-by-name/http-request.adoc[]
2128+
2129+
2130+
2131+
[[api-guide-resources-task-thin-executions-list-by-name-request-parameters]]
2132+
===== Request Parameters
2133+
2134+
include::{snippets}/task-executions-documentation/list-task-thin-executions-by-name/request-parameters.adoc[]
2135+
2136+
2137+
2138+
[[api-guide-resources-task-thin-executions-list-by-name-example-request]]
2139+
===== Example Request
2140+
2141+
include::{snippets}/task-executions-documentation/list-task-thin-executions-by-name/curl-request.adoc[]
2142+
2143+
2144+
2145+
[[api-guide-resources-task-thin-executions-list-by-name-response-structure]]
2146+
===== Response Structure
2147+
2148+
include::{snippets}/task-executions-documentation/list-task-thin-executions-by-name/http-response.adoc[]
20702149

20712150
[[api-guide-resources-task-executions-detail]]
20722151
==== Task Execution Detail

spring-cloud-dataflow-docs/src/main/asciidoc/configuration.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ spring:
661661
- DELETE /tasks/executions/* => hasRole('ROLE_DESTROY')
662662
663663
- GET /tasks/thinexecutions => hasRole('ROLE_VIEW')
664+
- GET /tasks/thinexecutions/* => hasRole('ROLE_VIEW')
664665
665666
# Task Schedules
666667

spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/TaskOperations.java

+6
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ public interface TaskOperations {
113113
*/
114114
PagedModel<TaskExecutionThinResource> thinExecutionList();
115115

116+
/**
117+
* List task executions filtered by task name.
118+
* @return the page of task executions for the given task name.
119+
*/
120+
PagedModel<TaskExecutionThinResource> thinExecutionListByTaskName(String taskName);
121+
116122
/**
117123
* List task executions known to the system filtered by task name.
118124
*

spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/TaskTemplate.java

+19
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ public class TaskTemplate implements TaskOperations {
7171

7272
private static final String THIN_EXECUTIONS_RELATION = "tasks/thinexecutions";
7373

74+
private static final String THIN_EXECUTIONS_BY_NAME_RELATION = "tasks/thinexecutions/name";
75+
7476
private static final String EXECUTIONS_CURRENT_RELATION = "tasks/executions/current";
7577

7678
private static final String EXECUTION_RELATION = "tasks/executions/execution";
@@ -97,6 +99,8 @@ public class TaskTemplate implements TaskOperations {
9799

98100
private final Link thinExecutionsLink;
99101

102+
private final Link thinExecutionsByNameLink;
103+
100104
private final Link executionLink;
101105

102106
private final Link executionLaunchLink;
@@ -160,6 +164,12 @@ public class TaskTemplate implements TaskOperations {
160164
} else {
161165
this.thinExecutionsLink = null;
162166
}
167+
if(resources.getLink(THIN_EXECUTIONS_BY_NAME_RELATION).isPresent()) {
168+
this.thinExecutionsByNameLink = resources.getLink(THIN_EXECUTIONS_BY_NAME_RELATION).get();
169+
} else {
170+
this.thinExecutionsByNameLink = null;
171+
}
172+
163173
if(resources.getLink(EXECUTION_LAUNCH_RELATION).isPresent()) {
164174
this.executionLaunchLink = resources.getLink(EXECUTION_LAUNCH_RELATION).get();
165175
} else {
@@ -275,6 +285,15 @@ public PagedModel<TaskExecutionThinResource> thinExecutionList() {
275285
}
276286
}
277287

288+
@Override
289+
public PagedModel<TaskExecutionThinResource> thinExecutionListByTaskName(String taskName) {
290+
if(thinExecutionsByNameLink != null) {
291+
return restTemplate.getForObject(thinExecutionsByNameLink.expand(taskName).getHref(), TaskExecutionThinResource.Page.class);
292+
} else {
293+
return restTemplate.getForObject(executionByNameLink.expand(taskName).getHref(), TaskExecutionThinResource.Page.class);
294+
}
295+
}
296+
278297
@Override
279298
public TaskExecutionResource.Page executionListByTaskName(String taskName) {
280299
return restTemplate.getForObject(executionByNameLink.expand(taskName).getHref(),

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowControllerAutoConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,8 @@ public TaskExecutionController taskExecutionController(
286286
}
287287

288288
@Bean
289-
public TaskExecutionThinController taskExecutionThinController(DataflowTaskExplorer taskExplorer) {
290-
return new TaskExecutionThinController(taskExplorer);
289+
public TaskExecutionThinController taskExecutionThinController(DataflowTaskExplorer taskExplorer, TaskDefinitionRepository taskDefinitionRepository) {
290+
return new TaskExecutionThinController(taskExplorer, taskDefinitionRepository);
291291
}
292292

293293
@Bean

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/RootController.java

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ public RootResource info() {
155155
root.add(linkTo(methodOn(TasksInfoController.class).getInfo(null, null, null)).withRel("tasks/info/executions"));
156156
root.add(linkTo(methodOn(TaskLogsController.class).getLog(null, null)).withRel("tasks/logs"));
157157
root.add(linkTo(methodOn(TaskExecutionThinController.class).listTasks(null, null)).withRel("tasks/thinexecutions"));
158+
root.add(linkTo(methodOn(TaskExecutionThinController.class).retrieveTasksByName(null,null, null)).withRel("tasks/thinexecutions/name"));
158159

159160
if (featuresProperties.isSchedulesEnabled()) {
160161
root.add(entityLinks.linkToCollectionResource(ScheduleInfoResource.class).withRel("tasks/schedules"));

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/TaskExecutionController.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,11 @@ public PagedModel<TaskExecutionResource> retrieveTasksByName(
185185
Pageable pageable,
186186
PagedResourcesAssembler<TaskJobExecutionRel> assembler
187187
) {
188+
long tasks = this.taskDefinitionRepository.countByTaskName(taskName);
189+
if(tasks == 0) {
190+
throw new NoSuchTaskDefinitionException(taskName);
191+
}
188192
validatePageable(pageable);
189-
this.taskDefinitionRepository.findById(taskName)
190-
.orElseThrow(() -> new NoSuchTaskDefinitionException(taskName));
191193
Page<TaskExecution> taskExecutions = this.explorer.findTaskExecutionsByName(taskName, pageable);
192194
Page<TaskJobExecutionRel> result = getPageableRelationships(taskExecutions, pageable);
193195
return assembler.toModel(result, this.taskAssembler);

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/TaskExecutionThinController.java

+23-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import org.springframework.cloud.dataflow.core.ThinTaskExecution;
2020
import org.springframework.cloud.dataflow.rest.resource.TaskExecutionThinResource;
21+
import org.springframework.cloud.dataflow.server.repository.NoSuchTaskDefinitionException;
22+
import org.springframework.cloud.dataflow.server.repository.TaskDefinitionRepository;
2123
import org.springframework.cloud.dataflow.server.task.DataflowTaskExplorer;
2224
import org.springframework.cloud.task.repository.TaskExecution;
2325
import org.springframework.data.domain.Page;
@@ -30,6 +32,7 @@
3032
import org.springframework.http.HttpStatus;
3133
import org.springframework.web.bind.annotation.GetMapping;
3234
import org.springframework.web.bind.annotation.RequestMapping;
35+
import org.springframework.web.bind.annotation.RequestParam;
3336
import org.springframework.web.bind.annotation.ResponseStatus;
3437
import org.springframework.web.bind.annotation.RestController;
3538

@@ -46,10 +49,12 @@
4649
public class TaskExecutionThinController {
4750

4851
private final DataflowTaskExplorer explorer;
52+
private final TaskDefinitionRepository taskDefinitionRepository;
4953
private final TaskExecutionThinResourceAssembler resourceAssembler;
5054

51-
public TaskExecutionThinController(DataflowTaskExplorer explorer) {
55+
public TaskExecutionThinController(DataflowTaskExplorer explorer, TaskDefinitionRepository taskDefinitionRepository) {
5256
this.explorer = explorer;
57+
this.taskDefinitionRepository = taskDefinitionRepository;
5358
this.resourceAssembler = new TaskExecutionThinResourceAssembler();
5459
}
5560

@@ -62,6 +67,23 @@ public PagedModel<TaskExecutionThinResource> listTasks(Pageable pageable, PagedR
6267
return pagedAssembler.toModel(thinTaskExecutions, resourceAssembler);
6368
}
6469

70+
@GetMapping(value = "", params = "name")
71+
@ResponseStatus(HttpStatus.OK)
72+
public PagedModel<TaskExecutionThinResource> retrieveTasksByName(
73+
@RequestParam("name") String taskName,
74+
Pageable pageable,
75+
PagedResourcesAssembler<ThinTaskExecution> pagedAssembler
76+
) {
77+
long tasks = this.taskDefinitionRepository.countByTaskName(taskName);
78+
if(tasks == 0) {
79+
throw new NoSuchTaskDefinitionException(taskName);
80+
}
81+
Page<TaskExecution> page = this.explorer.findTaskExecutionsByName(taskName, pageable);
82+
Page<ThinTaskExecution> thinTaskExecutions = new PageImpl<>(page.stream().map(ThinTaskExecution::new).toList(), pageable, page.getTotalElements());
83+
explorer.populateCtrStatus(thinTaskExecutions.getContent());
84+
return pagedAssembler.toModel(thinTaskExecutions, resourceAssembler);
85+
}
86+
6587
static class TaskExecutionThinResourceAssembler extends RepresentationModelAssemblerSupport<ThinTaskExecution, TaskExecutionThinResource> {
6688
public TaskExecutionThinResourceAssembler() {
6789
super(TaskExecutionThinController.class, TaskExecutionThinResource.class);

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/repository/TaskDefinitionRepository.java

+1
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ public interface TaskDefinitionRepository extends KeyValueRepository<TaskDefinit
4646
*/
4747
TaskDefinition findByTaskName(String name);
4848

49+
long countByTaskName(String taskName);
4950
}

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/task/impl/DefaultDataFlowTaskExecutionQueryDao.java

+13-14
Original file line numberDiff line numberDiff line change
@@ -522,20 +522,19 @@ private List<String> getTaskArguments(long taskExecutionId) {
522522

523523
@Override
524524
public void populateCtrStatus(Collection<ThinTaskExecution> thinTaskExecutions) {
525-
Map<Long, ThinTaskExecution> taskExecutionMap = thinTaskExecutions.stream()
525+
if(!thinTaskExecutions.isEmpty()) {
526+
Map<Long, ThinTaskExecution> taskExecutionMap = thinTaskExecutions.stream()
526527
.collect(Collectors.toMap(ThinTaskExecution::getExecutionId, Function.identity()));
527-
String ids = taskExecutionMap.keySet()
528-
.stream()
529-
.map(Object::toString)
530-
.collect(Collectors.joining(","));
531-
String sql = FIND_CTR_STATUS.replace(":taskExecutionIds", ids);
532-
jdbcTemplate.query(sql, rs -> {
533-
Long id = rs.getLong("TASK_EXECUTION_ID");
534-
String ctrStatus = rs.getString("CTR_STATUS");
535-
logger.debug("populateCtrStatus:{}={}", id, ctrStatus);
536-
ThinTaskExecution execution = taskExecutionMap.get(id);
537-
Assert.notNull(execution, "Expected TaskExecution for " + id + " from " + ids);
538-
execution.setCtrTaskStatus(ctrStatus);
539-
});
528+
String ids = taskExecutionMap.keySet().stream().map(Object::toString).collect(Collectors.joining(","));
529+
String sql = FIND_CTR_STATUS.replace(":taskExecutionIds", ids);
530+
jdbcTemplate.query(sql, rs -> {
531+
Long id = rs.getLong("TASK_EXECUTION_ID");
532+
String ctrStatus = rs.getString("CTR_STATUS");
533+
logger.debug("populateCtrStatus:{}={}", id, ctrStatus);
534+
ThinTaskExecution execution = taskExecutionMap.get(id);
535+
Assert.notNull(execution, "Expected TaskExecution for " + id + " from " + ids);
536+
execution.setCtrTaskStatus(ctrStatus);
537+
});
538+
}
540539
}
541540
}

spring-cloud-dataflow-server-core/src/main/resources/META-INF/dataflow-server-defaults.yml

+1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ spring:
241241
- GET /tasks/info/* => hasRole('ROLE_VIEW')
242242

243243
- GET /tasks/thinexecutions => hasRole('ROLE_VIEW')
244+
- GET /tasks/thinexecutions/* => hasRole('ROLE_VIEW')
244245

245246
# Task Schedules
246247

spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@ public TaskExecutionController taskExecutionController(
270270
}
271271

272272
@Bean
273-
public TaskExecutionThinController taskExecutionThinController(DataflowTaskExplorer dataflowTaskExplorer) {
274-
return new TaskExecutionThinController(dataflowTaskExplorer);
273+
public TaskExecutionThinController taskExecutionThinController(DataflowTaskExplorer dataflowTaskExplorer, TaskDefinitionRepository taskDefinitionRepository) {
274+
return new TaskExecutionThinController(dataflowTaskExplorer, taskDefinitionRepository);
275275
}
276276

277277
@Bean

spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/TestDependencies.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,8 @@ public TaskExecutionController taskExecutionController(
593593
}
594594

595595
@Bean
596-
public TaskExecutionThinController taskExecutionThinController(DataflowTaskExplorer dataflowTaskExplorer) {
597-
return new TaskExecutionThinController(dataflowTaskExplorer);
596+
public TaskExecutionThinController taskExecutionThinController(DataflowTaskExplorer dataflowTaskExplorer, TaskDefinitionRepository taskDefinitionRepository) {
597+
return new TaskExecutionThinController(dataflowTaskExplorer, taskDefinitionRepository);
598598
}
599599
@Bean
600600
public TasksInfoController taskExecutionsInfoController(TaskExecutionService taskExecutionService) {

0 commit comments

Comments
 (0)