Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Threading;
using System.Threading.Tasks;
using EnsureThat;
using MediatR;

namespace Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus
{
/// <summary>
/// Handler for getting all async job statuses.
/// </summary>
public class GetAllJobStatusHandler : IRequestHandler<GetAllJobStatusRequest, GetAllJobStatusResponse>
{
private readonly IJobStatusService _jobStatusService;

/// <summary>
/// Initializes a new instance of the <see cref="GetAllJobStatusHandler"/> class.
/// </summary>
/// <param name="jobStatusService">The job status service.</param>
public GetAllJobStatusHandler(IJobStatusService jobStatusService)
{
_jobStatusService = EnsureArg.IsNotNull(jobStatusService, nameof(jobStatusService));
}

/// <inheritdoc />
public async Task<GetAllJobStatusResponse> Handle(GetAllJobStatusRequest request, CancellationToken cancellationToken)
{
EnsureArg.IsNotNull(request, nameof(request));

var jobs = await _jobStatusService.GetAllJobStatusAsync(cancellationToken);

return new GetAllJobStatusResponse(jobs);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using MediatR;

namespace Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus
{
/// <summary>
/// Request to get all async job statuses.
/// </summary>
public class GetAllJobStatusRequest : IRequest<GetAllJobStatusResponse>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Collections.Generic;

namespace Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus
{
/// <summary>
/// Represents the response containing a list of job status information.
/// </summary>
public class GetAllJobStatusResponse
{
/// <summary>
/// Initializes a new instance of the <see cref="GetAllJobStatusResponse"/> class.
/// </summary>
/// <param name="jobs">The list of job status information.</param>
public GetAllJobStatusResponse(IReadOnlyList<JobStatusInfo> jobs)
{
Jobs = jobs;
}

/// <summary>
/// Gets the list of job status information.
/// </summary>
public IReadOnlyList<JobStatusInfo> Jobs { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus
{
/// <summary>
/// Service interface for retrieving job status information.
/// </summary>
public interface IJobStatusService
{
/// <summary>
/// Gets the status information for all async jobs (Export, Import, Reindex, BulkDelete, BulkUpdate).
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A list of job status information.</returns>
Task<IReadOnlyList<JobStatusInfo>> GetAllJobStatusAsync(CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using Microsoft.Health.JobManagement;

namespace Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus
{
/// <summary>
/// Represents the status information for an async job.
/// </summary>
public class JobStatusInfo
{
/// <summary>
/// Gets or sets the group identifier for the job.
/// </summary>
public long GroupId { get; set; }

/// <summary>
/// Gets or sets the type of the job (e.g., Export, Import, Reindex).
/// </summary>
public string JobType { get; set; }

/// <summary>
/// Gets or sets the queue type.
/// </summary>
public QueueType QueueType { get; set; }

/// <summary>
/// Gets or sets the status of the job.
/// </summary>
public Microsoft.Health.JobManagement.JobStatus Status { get; set; }

/// <summary>
/// Gets or sets the content location URL for the job.
/// </summary>
public Uri ContentLocation { get; set; }

/// <summary>
/// Gets or sets the date and time when the job was created.
/// </summary>
public DateTime CreateDate { get; set; }

/// <summary>
/// Gets or sets the date and time when the job ended.
/// </summary>
public DateTime? EndDate { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public static class OperationsConstants

public const string ValueSetExpand = $"valueset-expand";

public const string Jobs = "jobs";

public static readonly ReadOnlyCollection<string> ExcludedResourceTypesForBulkUpdate = new ReadOnlyCollection<string>(new[] { "SearchParameter", "StructureDefinition" });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,7 @@ internal class KnownRoutes
public const string ExpandResourceType = KnownResourceTypes.ValueSet + "/" + Expand;
public const string ExpandResourceId = KnownResourceTypes.ValueSet + "/" + IdRouteSegment + "/" + Expand;
public const string ExpandOperationDefinition = OperationDefinition + "/" + OperationsConstants.ValueSetExpand;

public const string JobStatus = OperationsConstants.Operations + "/" + OperationsConstants.Jobs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,7 @@ internal static class RouteNames
internal const string ExpandById = nameof(ExpandById);

internal const string ExpandDefinition = nameof(ExpandDefinition);

internal const string GetAllJobStatus = nameof(GetAllJobStatus);
}
}
11 changes: 10 additions & 1 deletion src/Microsoft.Health.Fhir.Core/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion src/Microsoft.Health.Fhir.Core/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -870,4 +870,8 @@
<data name="ReindexingNoSearchParameterstoReindex" xml:space="preserve">
<value>There are no search parameters to reindex for job Id: {0}.</value>
</data>
</root>
<data name="JobStatusNotSupportedForCosmosDb" xml:space="preserve">
<value>The job status endpoint is not supported for Cosmos DB deployments.</value>
<comment>Error message when job status endpoint is called on a Cosmos DB deployment</comment>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus;

namespace Microsoft.Health.Fhir.CosmosDb.Features.Operations
{
/// <summary>
/// Cosmos DB implementation of the job status service.
/// This feature is not supported on Cosmos DB.
/// </summary>
public class CosmosJobStatusService : IJobStatusService
{
/// <inheritdoc />
public Task<IReadOnlyList<JobStatusInfo>> GetAllJobStatusAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException(Fhir.Core.Resources.JobStatusNotSupportedForCosmosDb);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Threading.Tasks;
using EnsureThat;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Health.Api.Features.Audit;
using Microsoft.Health.Fhir.Api.Features.ActionResults;
using Microsoft.Health.Fhir.Api.Features.Filters;
using Microsoft.Health.Fhir.Api.Features.Resources;
using Microsoft.Health.Fhir.Api.Features.Routing;
using Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus;
using Microsoft.Health.Fhir.Core.Features.Routing;
using Microsoft.Health.Fhir.ValueSets;

namespace Microsoft.Health.Fhir.Api.Controllers
{
/// <summary>
/// Controller for retrieving job status information.
/// </summary>
[ServiceFilter(typeof(AuditLoggingFilterAttribute))]
[ServiceFilter(typeof(OperationOutcomeExceptionFilterAttribute))]
[ValidateModelState]
public class JobStatusController : Controller
{
private readonly IMediator _mediator;

/// <summary>
/// Initializes a new instance of the <see cref="JobStatusController"/> class.
/// </summary>
/// <param name="mediator">The mediator.</param>
public JobStatusController(IMediator mediator)
{
_mediator = EnsureArg.IsNotNull(mediator, nameof(mediator));
}

/// <summary>
/// Gets the status of all async jobs (Export, Import, Reindex, BulkDelete, BulkUpdate).
/// </summary>
/// <returns>A list of job status information.</returns>
[HttpGet]
[Route(KnownRoutes.JobStatus, Name = RouteNames.GetAllJobStatus)]
[AuditEventType(AuditEventSubType.Read)]
public async Task<IActionResult> GetAllJobStatus()
{
var response = await _mediator.Send(new GetAllJobStatusRequest(), HttpContext.RequestAborted);

return FhirResult.Create(response.Jobs.ToJobStatusResult());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using Hl7.Fhir.Model;
using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Operations.GetJobStatus;
using Microsoft.Health.Fhir.Core.Models;

namespace Microsoft.Health.Fhir.Api.Features.Resources
{
/// <summary>
/// Extension methods for job status responses.
/// </summary>
public static class JobStatusResponseExtensions
{
/// <summary>
/// Converts a list of JobStatusInfo to a FHIR Parameters resource.
/// </summary>
/// <param name="jobs">The list of job status information.</param>
/// <returns>A FHIR Parameters resource as a ResourceElement</returns>
public static ResourceElement ToJobStatusResult(this IReadOnlyList<JobStatusInfo> jobs)
{
var parameters = new Parameters();

foreach (var job in jobs)
{
var part = new Parameters.ParameterComponent
{
Name = job.JobType + " " + job.GroupId,
};

part.Part.Add(new Parameters.ParameterComponent
{
Name = "id",
Value = new Integer64(job.GroupId),
});

part.Part.Add(new Parameters.ParameterComponent
{
Name = "type",
Value = new FhirString(job.JobType),
});

part.Part.Add(new Parameters.ParameterComponent
{
Name = "uri",
Value = new FhirUri(job.ContentLocation),
});

part.Part.Add(new Parameters.ParameterComponent
{
Name = "status",
Value = new FhirString(job.Status.ToString()),
});

part.Part.Add(new Parameters.ParameterComponent
{
Name = "createTime",
Value = new FhirDateTime(job.CreateDate),
});

if (job.EndDate != null)
{
part.Part.Add(new Parameters.ParameterComponent
{
Name = "endTime",
Value = new FhirDateTime((System.DateTimeOffset)job.EndDate),
});
}

parameters.Parameter.Add(part);
}

return parameters.ToResourceElement();
}
}
}
Loading
Loading