-
Notifications
You must be signed in to change notification settings - Fork 544
Fix $bulk-delete bugs with custom search parameter #4964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
aa190d4
62daa03
53acd9b
d4ae388
21b8701
179274e
6917021
4536421
d4a5874
af3484b
ff8250c
19439a2
8e982d9
06beb09
8e54cb9
942c800
95e9407
3bd595d
026b92a
c6067b9
5814c29
ce0000f
835a8af
bb6dee4
cebd7cf
6d65aab
792169b
27088a9
17dc3da
66d833e
ea18303
220dacf
b205575
6c4a4c6
228156d
98a8a1a
5c9c27f
59cb78a
2ec5767
9706ecc
373b00e
5ece706
6144df2
a771700
1feb027
13f5de0
0b0877f
48fe44f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,24 +6,29 @@ | |
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text.Json; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using EnsureThat; | ||
using Hl7.Fhir.ElementModel; | ||
using MediatR; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Health.Extensions.DependencyInjection; | ||
using Microsoft.Health.Fhir.Core.Exceptions; | ||
using Microsoft.Health.Fhir.Core.Extensions; | ||
using Microsoft.Health.Fhir.Core.Features.Definition; | ||
using Microsoft.Health.Fhir.Core.Features.Definition.BundleWrappers; | ||
using Microsoft.Health.Fhir.Core.Features.Operations.BulkDelete.Messages; | ||
using Microsoft.Health.Fhir.Core.Features.Persistence; | ||
using Microsoft.Health.Fhir.Core.Features.Search.Registry; | ||
using Microsoft.Health.Fhir.Core.Models; | ||
|
||
namespace Microsoft.Health.Fhir.Core.Features.Search.Parameters | ||
{ | ||
public class SearchParameterOperations : ISearchParameterOperations | ||
public class SearchParameterOperations : ISearchParameterOperations, INotificationHandler<BulkDeleteMetricsNotification> | ||
{ | ||
private const int DefaultDeleteTasksPerPage = 5; | ||
|
||
private readonly ISearchParameterDefinitionManager _searchParameterDefinitionManager; | ||
private readonly SearchParameterStatusManager _searchParameterStatusManager; | ||
private readonly IModelInfoProvider _modelInfoProvider; | ||
|
@@ -278,6 +283,27 @@ await _searchParameterStatusManager.ApplySearchParameterStatus( | |
cancellationToken); | ||
} | ||
|
||
public async Task Handle(BulkDeleteMetricsNotification notification, CancellationToken cancellationToken) | ||
{ | ||
var content = notification?.Content?.ToString(); | ||
if (!string.IsNullOrWhiteSpace(content)) | ||
{ | ||
try | ||
{ | ||
var urls = JsonSerializer.Deserialize<List<string>>(content); | ||
if (urls.Any()) | ||
{ | ||
await DeleteSearchParametersAsync(urls, DefaultDeleteTasksPerPage, cancellationToken); | ||
} | ||
} | ||
catch (JsonException ex) | ||
{ | ||
_logger.LogError(ex, "Failed to deserialize the notification content."); | ||
throw; | ||
} | ||
} | ||
} | ||
|
||
private void DeleteSearchParameter(string url) | ||
{ | ||
try | ||
|
@@ -311,5 +337,69 @@ private async Task<ITypedElement> GetSearchParameterByUrl(string url, Cancellati | |
|
||
return null; | ||
} | ||
|
||
private async Task DeleteSearchParametersAsync(List<string> urls, int pageSize, CancellationToken cancellationToken) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like how there are a DeleteSearchParameter and DeleteSearchParametersAsync methods in the same class that do different things. Could this method be DeleteSearchParametersFromDatabaseAsync? I'm not thrilled with this, but it helps show the two methods are doing different things. |
||
{ | ||
if (urls?.Any() ?? false) | ||
{ | ||
// We need to make sure we have the latest search parameters before trying to delete | ||
// existing search parameter. This is to avoid trying to update a search parameter that | ||
// was recently added and that hasn't propogated to all fhir-server instances. | ||
await GetAndApplySearchParameterUpdates(cancellationToken); | ||
|
||
var count = 0; | ||
while (count < urls.Count) | ||
{ | ||
var urlsToDelete = urls.Skip(count).Take(pageSize).ToList(); | ||
count += urlsToDelete.Count; | ||
|
||
var tasks = new List<Task>(); | ||
foreach (var url in urlsToDelete) | ||
{ | ||
if (string.IsNullOrWhiteSpace(url)) | ||
{ | ||
_logger.LogWarning("Skipping the null or empty url."); | ||
continue; | ||
} | ||
|
||
tasks.Add( | ||
Task.Run( | ||
async () => | ||
{ | ||
try | ||
{ | ||
// First we delete the status metadata from the data store as this function depends on | ||
// the in memory definition manager. Once complete we remove the SearchParameter from | ||
// the definition manager. | ||
_logger.LogInformation("Deleting the search parameter '{Url}'", url); | ||
await _searchParameterStatusManager.UpdateSearchParameterStatusAsync(new List<string>() { url }, SearchParameterStatus.PendingDelete, cancellationToken); | ||
|
||
// Update the status of the search parameter in the definition manager once the status is updated in the store. | ||
_searchParameterDefinitionManager.UpdateSearchParameterStatus(url, SearchParameterStatus.PendingDelete); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError(ex, $"Failed to delete a search parameter with url: {url}"); | ||
throw; | ||
} | ||
}, | ||
cancellationToken)); | ||
} | ||
|
||
try | ||
{ | ||
if (tasks.Any()) | ||
{ | ||
await Task.WhenAll(tasks); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError(ex, $"Failed to delete {tasks.Where(x => !x.IsCompleted).Count()} search parameters."); | ||
throw; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.