Skip to content

Commit

Permalink
Merge pull request #776 from Project-MONAI/AC-2010
Browse files Browse the repository at this point in the history
AC-2010 Update get payloads endpoint
  • Loading branch information
samrooke authored May 4, 2023
2 parents 57773bc + 063d70c commit 51836fd
Show file tree
Hide file tree
Showing 18 changed files with 429 additions and 52 deletions.
180 changes: 170 additions & 10 deletions docs/api/rest/workflow-manager/payload.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,197 @@

# Workflow Manager - Payload APIs

**TEMPLATE**
## GET /payloads

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

*description*
- If any of the workflow Instances status' attached to that payload are “Created” then the payloadStatus would be “In Progress”

- If all workflow Instances status' attached to that payload are not “Created” then the payloadStatus would be “Complete”

- If there are no workflow Instances attached to that payload then the payloadStatus would be “Complete”

### Parameters

*parameters*
(Query) pageNumber: int

(Query) pageSize: int

(Query) maxPageSize: int (default of 10)

(Query) patientId: string

(Query) patientName: string

### Responses

Response Content Type: JSON

*response type*

| Code | Description |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------- |
| 200 | Service is healthy. |
| 503 | Service is unhealthy. |
| 200 | List of payloads. |
| 500 | Server error. The response will be a [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) object with server error details. |

### Example Request

```bash
curl --location --request GET 'http://localhost:5000/workflows'
curl --location --request GET 'http://localhost:5000/payloads'
```

### Example Response

```json
*sample output*
{
"PageNumber": 1,
"PageSize": 10,
"FirstPage": "/payload?pageNumber=1&pageSize=10",
"LastPage": "/payload?pageNumber=1&pageSize=10",
"TotalPages": 1,
"TotalRecords": 3,
"NextPage": null,
"PreviousPage": null,
"Data":
[
{
"Version": "1.0.0",
"id": "3042cac6-b8b8-4f65-a2b2-8ec340652c9b",
"payload_id": "c5c3636b-81dd-44a9-8c4b-71adec7d47b2",
"workflows": ["1e7b49f2-a3a2-4ded-b489-86ad9b2da9c8"],
"workflow_instance_ids": [],
"file_count": 50,
"correlation_id": "68ccea88-1f40-4eb3-ad23-7f444ac12910",
"bucket": "bucket_1",
"calling_aetitle": "Basic_AE",
"called_aetitle": "MIG",
"timestamp": "2023-05-03T12:47:59.046Z",
"files": [],
"patient_details":
{
"patient_id": "732ca351-6267-41e9-a6e8-21b3a74abe7c",
"patient_name": "Steve Jobs",
"patient_sex": "male",
"patient_dob": "1996-02-05T00:00:00Z",
"patient_age": null,
"patient_hospital_id": null
},
"payload_status": "Completed",
"payload_deleted": 1
},
{
"Version": "1.0.0",
"id": "2435a8d7-84f4-407d-9d0e-941bb87b0190",
"payload_id": "86c0f117-4021-412e-b163-0dc621df672a",
"workflows": ["3d517d26-118c-4241-beb8-6b51d462c746"],
"workflow_instance_ids": [],
"file_count": 3,
"correlation_id": "1ef12067-0fda-45c6-87b4-bcc4b245e8d9",
"bucket": "bucket_1",
"calling_aetitle": "Basic_AE",
"called_aetitle": "MIG",
"timestamp": "2023-05-03T12:47:59.046Z",
"files": [],
"patient_details":
{
"patient_id": "dae4a6d1-573d-4a3f-978f-ed056f628de6",
"patient_name": "Jane Doe",
"patient_sex": "female",
"patient_dob": null,
"patient_age": null,
"patient_hospital_id": null
},
"payload_status": "Completed",
"payload_deleted": 1
},
{
"Version": "1.0.0",
"id": "39d599bc-6635-4f94-9b55-b72a5b11c849",
"payload_id": "30a8e0c6-e6c4-458f-aa4d-b224b493d3c0",
"workflows": ["db52fafe-1035-436a-b4ff-50ab850f5f68"],
"workflow_instance_ids": [],
"file_count": 3,
"correlation_id": "40544d26-b4bb-4f67-b4ae-68ff3a237cf2",
"bucket": "bucket_2",
"calling_aetitle": "Basic_AE",
"called_aetitle": "MIG",
"timestamp": "2023-05-03T12:47:59.046Z",
"files": [],
"patient_details":
{
"patient_id": null,
"patient_name": null,
"patient_sex": null,
"patient_dob": null,
"patient_age": null,
"patient_hospital_id": null
},
"payload_status": "Completed",
"payload_deleted": 1
}
],
"Succeeded": true,
"Errors": null,
"Message": null
}
```

---

## GET /payloads/{id}

Returns specific payload for given id.

### Parameters
(Route) id: string - UUID

### Responses

Response Content Type: JSON

| Code | Description |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------- |
| 200 | List of payloads. |
| 400 | [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) Failed to validate id. |
| 404 | [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) Failed to find payload with payload id. |
| 500 | Server error. The response will be a [Problem details](https://datatracker.ietf.org/doc/html/rfc7807) object with server error details. |


### Example Request

```bash
curl --location --request GET 'http://localhost:5000/payloads/3042cac6-b8b8-4f65-a2b2-8ec340652c9b'
```

### Example Response
```json
{
"Version": "1.0.0",
"id": "3042cac6-b8b8-4f65-a2b2-8ec340652c9b",
"payload_id": "c5c3636b-81dd-44a9-8c4b-71adec7d47b2",
"workflows": ["1e7b49f2-a3a2-4ded-b489-86ad9b2da9c8"],
"workflow_instance_ids": [],
"file_count": 50,
"correlation_id": "68ccea88-1f40-4eb3-ad23-7f444ac12910",
"bucket": "bucket_1",
"calling_aetitle": "Basic_AE",
"called_aetitle": "MIG",
"timestamp": "2023-05-03T12:47:59.046Z",
"files": [],
"patient_details":
{
"patient_id": "732ca351-6267-41e9-a6e8-21b3a74abe7c",
"patient_name": "Steve Jobs",
"patient_sex": "male",
"patient_dob": "1996-02-05T00:00:00Z",
"patient_age": null,
"patient_hospital_id": null
},
}
```

---

## DELETE /payloads/{id}

TODO

---
5 changes: 3 additions & 2 deletions src/WorkflowManager/Common/Interfaces/IPayloadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

namespace Monai.Deploy.WorkflowManager.Common.Interfaces
{
public interface IPayloadService : IPaginatedApi<Payload>
public interface IPayloadService : IPaginatedApi<PayloadDto>
{
/// <summary>
/// Creates a payload and appends patient details.
Expand All @@ -36,10 +36,11 @@ public interface IPayloadService : IPaginatedApi<Payload>
/// <summary>
/// Gets a list of payloads.
/// </summary>
Task<IList<Payload>> GetAllAsync(int? skip = null,
Task<IList<PayloadDto>> GetAllAsync(int? skip = null,
int? limit = null,
string? patientId = "",
string? patientName = "");
new Task<IList<PayloadDto>> GetAllAsync(int? skip = null, int? limit = null);

/// <summary>
/// Deletes a payload by id.
Expand Down
58 changes: 50 additions & 8 deletions src/WorkflowManager/Common/Services/PayloadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ namespace Monai.Deploy.WorkflowManager.Common.Services
{
public class PayloadService : IPayloadService
{
private readonly IPayloadRepsitory _payloadRepository;
private readonly IPayloadRepository _payloadRepository;

private readonly IWorkflowInstanceRepository _workflowInstanceRepository;

private readonly IDicomService _dicomService;

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

public PayloadService(
IPayloadRepsitory payloadRepsitory,
IPayloadRepository payloadRepository,
IDicomService dicomService,
IWorkflowInstanceRepository workflowInstanceRepository,
IServiceScopeFactory serviceScopeFactory,
ILogger<PayloadService> logger)
{
_payloadRepository = payloadRepsitory ?? throw new ArgumentNullException(nameof(payloadRepsitory));
_payloadRepository = payloadRepository ?? throw new ArgumentNullException(nameof(payloadRepository));
_workflowInstanceRepository = workflowInstanceRepository ?? throw new ArgumentNullException(nameof(workflowInstanceRepository));
_dicomService = dicomService ?? throw new ArgumentNullException(nameof(dicomService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));

Expand Down Expand Up @@ -81,7 +85,8 @@ public PayloadService(
CalledAeTitle = eventPayload.CalledAeTitle,
CallingAeTitle = eventPayload.CallingAeTitle,
Timestamp = eventPayload.Timestamp,
PatientDetails = patientDetails
PatientDetails = patientDetails,
PayloadDeleted = PayloadDeleted.No,
};

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

public async Task<IList<Payload>> GetAllAsync(int? skip = null,
public async Task<IList<PayloadDto>> GetAllAsync(int? skip = null,
int? limit = null,
string? patientId = "",
string? patientName = "")
=> await _payloadRepository.GetAllAsync(skip, limit, patientId, patientName);
=> await CreatePayloadsDto(
await _payloadRepository.GetAllAsync(skip, limit, patientId, patientName)
);

public async Task<IList<PayloadDto>> GetAllAsync(int? skip = null, int? limit = null)
=> await CreatePayloadsDto(await _payloadRepository.GetAllAsync(skip, limit));

private async Task<IList<PayloadDto>> CreatePayloadsDto(IList<Payload> payloads)
{
var dtos = new List<PayloadDto>();
if (payloads is null || payloads.Count == 0)
{
return dtos;
}

var payloadIds = payloads.Select(payload => payload.Id).ToList();

var workflowInstances =
await _workflowInstanceRepository.GetByPayloadIdsAsync(payloadIds);

foreach (var payload in payloads)
{
var payloadDto = new PayloadDto(payload);
var wfs = workflowInstances?.Where(wf => wf.PayloadId == payload.Id);
if (wfs == null || wfs.Any() is false)
{
payloadDto.PayloadStatus = PayloadStatus.Complete;
}
else if (wfs.Any(wf => wf.Status == Status.Created))
{
payloadDto.PayloadStatus = PayloadStatus.InProgress;
}
else if (wfs.All(wf => wf.Status != Status.Created))
{
payloadDto.PayloadStatus = PayloadStatus.Complete;
}
dtos.Add(payloadDto);
}

public async Task<IList<Payload>> GetAllAsync(int? skip = null, int? limit = null)
=> await _payloadRepository.GetAllAsync(skip, limit);
return dtos;
}

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

Expand Down
51 changes: 51 additions & 0 deletions src/WorkflowManager/Contracts/Models/PayloadDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2023 MONAI Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using Newtonsoft.Json;

namespace Monai.Deploy.WorkflowManager.Contracts.Models
{
public class PayloadDto : Payload
{
public PayloadDto() { }
public PayloadDto(Payload payload)
{
Version = payload.Version;
Id = payload.Id;
PayloadId = payload.PayloadId;
Workflows = payload.Workflows;
WorkflowInstanceIds = payload.WorkflowInstanceIds;
FileCount = payload.FileCount;
CorrelationId = payload.CorrelationId;
Bucket = payload.Bucket;
CallingAeTitle = payload.CallingAeTitle;
CalledAeTitle = payload.CalledAeTitle;
Timestamp = payload.Timestamp;
Files = payload.Files;
PatientDetails = payload.PatientDetails;
PayloadDeleted = payload.PayloadDeleted;
}

[JsonProperty(PropertyName = "payload_status")]
public PayloadStatus PayloadStatus { get; set; }
}

public enum PayloadStatus
{
InProgress,
Complete
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

namespace Monai.Deploy.WorkflowManager.Database.Interfaces
{
public interface IPayloadRepsitory
public interface IPayloadRepository
{
/// <summary>
/// Creates a payload in the database.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public interface ITaskExecutionStatsRepository
/// <param name="status">the status to get count of, or string.empty</param>
/// <returns>The count of all records in range</returns>
Task<long> GetStatsStatusCountAsync(DateTime start, DateTime endTime, string status = "", string workflowInstanceId = "", string taskId = "");

/// <summary>
/// Returns all stats in Failed or PartialFail status.
/// </summary>
Expand Down
Loading

0 comments on commit 51836fd

Please sign in to comment.