Skip to content

Commit 51836fd

Browse files
authored
Merge pull request #776 from Project-MONAI/AC-2010
AC-2010 Update get payloads endpoint
2 parents 57773bc + 063d70c commit 51836fd

File tree

18 files changed

+429
-52
lines changed

18 files changed

+429
-52
lines changed

docs/api/rest/workflow-manager/payload.md

+170-10
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,197 @@
1616

1717
# Workflow Manager - Payload APIs
1818

19-
**TEMPLATE**
19+
## GET /payloads
2020

21-
## GET/POST/PUT/DELETE /payloads/
21+
Returns a paginated list of Payloads with additional computed property of payloadStatus.
2222

23-
*description*
23+
- If any of the workflow Instances status' attached to that payload are “Created” then the payloadStatus would be “In Progress”
24+
25+
- If all workflow Instances status' attached to that payload are not “Created” then the payloadStatus would be “Complete”
26+
27+
- If there are no workflow Instances attached to that payload then the payloadStatus would be “Complete”
2428

2529
### Parameters
2630

27-
*parameters*
31+
(Query) pageNumber: int
32+
33+
(Query) pageSize: int
34+
35+
(Query) maxPageSize: int (default of 10)
36+
37+
(Query) patientId: string
38+
39+
(Query) patientName: string
2840

2941
### Responses
3042

3143
Response Content Type: JSON
3244

33-
*response type*
34-
3545
| Code | Description |
3646
| ---- | --------------------------------------------------------------------------------------------------------------------------------------- |
37-
| 200 | Service is healthy. |
38-
| 503 | Service is unhealthy. |
47+
| 200 | List of payloads. |
3948
| 500 | Server error. The response will be a [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) object with server error details. |
4049

4150
### Example Request
4251

4352
```bash
44-
curl --location --request GET 'http://localhost:5000/workflows'
53+
curl --location --request GET 'http://localhost:5000/payloads'
4554
```
4655

4756
### Example Response
4857

4958
```json
50-
*sample output*
59+
{
60+
"PageNumber": 1,
61+
"PageSize": 10,
62+
"FirstPage": "/payload?pageNumber=1&pageSize=10",
63+
"LastPage": "/payload?pageNumber=1&pageSize=10",
64+
"TotalPages": 1,
65+
"TotalRecords": 3,
66+
"NextPage": null,
67+
"PreviousPage": null,
68+
"Data":
69+
[
70+
{
71+
"Version": "1.0.0",
72+
"id": "3042cac6-b8b8-4f65-a2b2-8ec340652c9b",
73+
"payload_id": "c5c3636b-81dd-44a9-8c4b-71adec7d47b2",
74+
"workflows": ["1e7b49f2-a3a2-4ded-b489-86ad9b2da9c8"],
75+
"workflow_instance_ids": [],
76+
"file_count": 50,
77+
"correlation_id": "68ccea88-1f40-4eb3-ad23-7f444ac12910",
78+
"bucket": "bucket_1",
79+
"calling_aetitle": "Basic_AE",
80+
"called_aetitle": "MIG",
81+
"timestamp": "2023-05-03T12:47:59.046Z",
82+
"files": [],
83+
"patient_details":
84+
{
85+
"patient_id": "732ca351-6267-41e9-a6e8-21b3a74abe7c",
86+
"patient_name": "Steve Jobs",
87+
"patient_sex": "male",
88+
"patient_dob": "1996-02-05T00:00:00Z",
89+
"patient_age": null,
90+
"patient_hospital_id": null
91+
},
92+
"payload_status": "Completed",
93+
"payload_deleted": 1
94+
},
95+
{
96+
"Version": "1.0.0",
97+
"id": "2435a8d7-84f4-407d-9d0e-941bb87b0190",
98+
"payload_id": "86c0f117-4021-412e-b163-0dc621df672a",
99+
"workflows": ["3d517d26-118c-4241-beb8-6b51d462c746"],
100+
"workflow_instance_ids": [],
101+
"file_count": 3,
102+
"correlation_id": "1ef12067-0fda-45c6-87b4-bcc4b245e8d9",
103+
"bucket": "bucket_1",
104+
"calling_aetitle": "Basic_AE",
105+
"called_aetitle": "MIG",
106+
"timestamp": "2023-05-03T12:47:59.046Z",
107+
"files": [],
108+
"patient_details":
109+
{
110+
"patient_id": "dae4a6d1-573d-4a3f-978f-ed056f628de6",
111+
"patient_name": "Jane Doe",
112+
"patient_sex": "female",
113+
"patient_dob": null,
114+
"patient_age": null,
115+
"patient_hospital_id": null
116+
},
117+
"payload_status": "Completed",
118+
"payload_deleted": 1
119+
},
120+
{
121+
"Version": "1.0.0",
122+
"id": "39d599bc-6635-4f94-9b55-b72a5b11c849",
123+
"payload_id": "30a8e0c6-e6c4-458f-aa4d-b224b493d3c0",
124+
"workflows": ["db52fafe-1035-436a-b4ff-50ab850f5f68"],
125+
"workflow_instance_ids": [],
126+
"file_count": 3,
127+
"correlation_id": "40544d26-b4bb-4f67-b4ae-68ff3a237cf2",
128+
"bucket": "bucket_2",
129+
"calling_aetitle": "Basic_AE",
130+
"called_aetitle": "MIG",
131+
"timestamp": "2023-05-03T12:47:59.046Z",
132+
"files": [],
133+
"patient_details":
134+
{
135+
"patient_id": null,
136+
"patient_name": null,
137+
"patient_sex": null,
138+
"patient_dob": null,
139+
"patient_age": null,
140+
"patient_hospital_id": null
141+
},
142+
"payload_status": "Completed",
143+
"payload_deleted": 1
144+
}
145+
],
146+
"Succeeded": true,
147+
"Errors": null,
148+
"Message": null
149+
}
51150
```
52151

152+
---
153+
154+
## GET /payloads/{id}
155+
156+
Returns specific payload for given id.
157+
158+
### Parameters
159+
(Route) id: string - UUID
160+
161+
### Responses
162+
163+
Response Content Type: JSON
164+
165+
| Code | Description |
166+
| ---- | --------------------------------------------------------------------------------------------------------------------------------------- |
167+
| 200 | List of payloads. |
168+
| 400 | [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) Failed to validate id. |
169+
| 404 | [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) Failed to find payload with payload id. |
170+
| 500 | Server error. The response will be a [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) object with server error details. |
171+
172+
173+
### Example Request
174+
175+
```bash
176+
curl --location --request GET 'http://localhost:5000/payloads/3042cac6-b8b8-4f65-a2b2-8ec340652c9b'
177+
```
178+
179+
### Example Response
180+
```json
181+
{
182+
"Version": "1.0.0",
183+
"id": "3042cac6-b8b8-4f65-a2b2-8ec340652c9b",
184+
"payload_id": "c5c3636b-81dd-44a9-8c4b-71adec7d47b2",
185+
"workflows": ["1e7b49f2-a3a2-4ded-b489-86ad9b2da9c8"],
186+
"workflow_instance_ids": [],
187+
"file_count": 50,
188+
"correlation_id": "68ccea88-1f40-4eb3-ad23-7f444ac12910",
189+
"bucket": "bucket_1",
190+
"calling_aetitle": "Basic_AE",
191+
"called_aetitle": "MIG",
192+
"timestamp": "2023-05-03T12:47:59.046Z",
193+
"files": [],
194+
"patient_details":
195+
{
196+
"patient_id": "732ca351-6267-41e9-a6e8-21b3a74abe7c",
197+
"patient_name": "Steve Jobs",
198+
"patient_sex": "male",
199+
"patient_dob": "1996-02-05T00:00:00Z",
200+
"patient_age": null,
201+
"patient_hospital_id": null
202+
},
203+
}
204+
```
205+
206+
---
207+
208+
## DELETE /payloads/{id}
209+
210+
TODO
211+
212+
---

src/WorkflowManager/Common/Interfaces/IPayloadService.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
namespace Monai.Deploy.WorkflowManager.Common.Interfaces
2121
{
22-
public interface IPayloadService : IPaginatedApi<Payload>
22+
public interface IPayloadService : IPaginatedApi<PayloadDto>
2323
{
2424
/// <summary>
2525
/// Creates a payload and appends patient details.
@@ -36,10 +36,11 @@ public interface IPayloadService : IPaginatedApi<Payload>
3636
/// <summary>
3737
/// Gets a list of payloads.
3838
/// </summary>
39-
Task<IList<Payload>> GetAllAsync(int? skip = null,
39+
Task<IList<PayloadDto>> GetAllAsync(int? skip = null,
4040
int? limit = null,
4141
string? patientId = "",
4242
string? patientName = "");
43+
new Task<IList<PayloadDto>> GetAllAsync(int? skip = null, int? limit = null);
4344

4445
/// <summary>
4546
/// Deletes a payload by id.

src/WorkflowManager/Common/Services/PayloadService.cs

+50-8
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ namespace Monai.Deploy.WorkflowManager.Common.Services
3030
{
3131
public class PayloadService : IPayloadService
3232
{
33-
private readonly IPayloadRepsitory _payloadRepository;
33+
private readonly IPayloadRepository _payloadRepository;
34+
35+
private readonly IWorkflowInstanceRepository _workflowInstanceRepository;
3436

3537
private readonly IDicomService _dicomService;
3638

@@ -39,12 +41,14 @@ public class PayloadService : IPayloadService
3941
private readonly ILogger<PayloadService> _logger;
4042

4143
public PayloadService(
42-
IPayloadRepsitory payloadRepsitory,
44+
IPayloadRepository payloadRepository,
4345
IDicomService dicomService,
46+
IWorkflowInstanceRepository workflowInstanceRepository,
4447
IServiceScopeFactory serviceScopeFactory,
4548
ILogger<PayloadService> logger)
4649
{
47-
_payloadRepository = payloadRepsitory ?? throw new ArgumentNullException(nameof(payloadRepsitory));
50+
_payloadRepository = payloadRepository ?? throw new ArgumentNullException(nameof(payloadRepository));
51+
_workflowInstanceRepository = workflowInstanceRepository ?? throw new ArgumentNullException(nameof(workflowInstanceRepository));
4852
_dicomService = dicomService ?? throw new ArgumentNullException(nameof(dicomService));
4953
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
5054

@@ -81,7 +85,8 @@ public PayloadService(
8185
CalledAeTitle = eventPayload.CalledAeTitle,
8286
CallingAeTitle = eventPayload.CallingAeTitle,
8387
Timestamp = eventPayload.Timestamp,
84-
PatientDetails = patientDetails
88+
PatientDetails = patientDetails,
89+
PayloadDeleted = PayloadDeleted.No,
8590
};
8691

8792
if (await _payloadRepository.CreateAsync(payload))
@@ -109,14 +114,51 @@ public async Task<Payload> GetByIdAsync(string payloadId)
109114
return await _payloadRepository.GetByIdAsync(payloadId);
110115
}
111116

112-
public async Task<IList<Payload>> GetAllAsync(int? skip = null,
117+
public async Task<IList<PayloadDto>> GetAllAsync(int? skip = null,
113118
int? limit = null,
114119
string? patientId = "",
115120
string? patientName = "")
116-
=> await _payloadRepository.GetAllAsync(skip, limit, patientId, patientName);
121+
=> await CreatePayloadsDto(
122+
await _payloadRepository.GetAllAsync(skip, limit, patientId, patientName)
123+
);
124+
125+
public async Task<IList<PayloadDto>> GetAllAsync(int? skip = null, int? limit = null)
126+
=> await CreatePayloadsDto(await _payloadRepository.GetAllAsync(skip, limit));
127+
128+
private async Task<IList<PayloadDto>> CreatePayloadsDto(IList<Payload> payloads)
129+
{
130+
var dtos = new List<PayloadDto>();
131+
if (payloads is null || payloads.Count == 0)
132+
{
133+
return dtos;
134+
}
135+
136+
var payloadIds = payloads.Select(payload => payload.Id).ToList();
137+
138+
var workflowInstances =
139+
await _workflowInstanceRepository.GetByPayloadIdsAsync(payloadIds);
140+
141+
foreach (var payload in payloads)
142+
{
143+
var payloadDto = new PayloadDto(payload);
144+
var wfs = workflowInstances?.Where(wf => wf.PayloadId == payload.Id);
145+
if (wfs == null || wfs.Any() is false)
146+
{
147+
payloadDto.PayloadStatus = PayloadStatus.Complete;
148+
}
149+
else if (wfs.Any(wf => wf.Status == Status.Created))
150+
{
151+
payloadDto.PayloadStatus = PayloadStatus.InProgress;
152+
}
153+
else if (wfs.All(wf => wf.Status != Status.Created))
154+
{
155+
payloadDto.PayloadStatus = PayloadStatus.Complete;
156+
}
157+
dtos.Add(payloadDto);
158+
}
117159

118-
public async Task<IList<Payload>> GetAllAsync(int? skip = null, int? limit = null)
119-
=> await _payloadRepository.GetAllAsync(skip, limit);
160+
return dtos;
161+
}
120162

121163
public async Task<long> CountAsync() => await _payloadRepository.CountAsync();
122164

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2023 MONAI Consortium
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using Newtonsoft.Json;
18+
19+
namespace Monai.Deploy.WorkflowManager.Contracts.Models
20+
{
21+
public class PayloadDto : Payload
22+
{
23+
public PayloadDto() { }
24+
public PayloadDto(Payload payload)
25+
{
26+
Version = payload.Version;
27+
Id = payload.Id;
28+
PayloadId = payload.PayloadId;
29+
Workflows = payload.Workflows;
30+
WorkflowInstanceIds = payload.WorkflowInstanceIds;
31+
FileCount = payload.FileCount;
32+
CorrelationId = payload.CorrelationId;
33+
Bucket = payload.Bucket;
34+
CallingAeTitle = payload.CallingAeTitle;
35+
CalledAeTitle = payload.CalledAeTitle;
36+
Timestamp = payload.Timestamp;
37+
Files = payload.Files;
38+
PatientDetails = payload.PatientDetails;
39+
PayloadDeleted = payload.PayloadDeleted;
40+
}
41+
42+
[JsonProperty(PropertyName = "payload_status")]
43+
public PayloadStatus PayloadStatus { get; set; }
44+
}
45+
46+
public enum PayloadStatus
47+
{
48+
InProgress,
49+
Complete
50+
}
51+
}

src/WorkflowManager/Database/Interfaces/IPayloadRepsitory.cs renamed to src/WorkflowManager/Database/Interfaces/IPayloadRepository.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
namespace Monai.Deploy.WorkflowManager.Database.Interfaces
2222
{
23-
public interface IPayloadRepsitory
23+
public interface IPayloadRepository
2424
{
2525
/// <summary>
2626
/// Creates a payload in the database.

src/WorkflowManager/Database/Interfaces/ITaskExecutionStatsRepository.cs

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public interface ITaskExecutionStatsRepository
6969
/// <param name="status">the status to get count of, or string.empty</param>
7070
/// <returns>The count of all records in range</returns>
7171
Task<long> GetStatsStatusCountAsync(DateTime start, DateTime endTime, string status = "", string workflowInstanceId = "", string taskId = "");
72+
7273
/// <summary>
7374
/// Returns all stats in Failed or PartialFail status.
7475
/// </summary>

0 commit comments

Comments
 (0)