Skip to content

Commit

Permalink
chore: Fix redundant call to resource registry API (#1181)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the Title above -->

## Description

<!--- Describe your changes in detail -->

This is due to the application caching two separate dictionaries of info
from the resource registry, grouped by different keys.

![CleanShot 2024-09-25 at 15 30
41@2x](https://github.com/user-attachments/assets/004eb728-3ed7-46d9-8b22-76f7dd7e6451)

Added caching of the raw response from the resource registry and removed
the dependent caches to lower complexity.

## Related Issue(s)

- #1136 

## Verification

- [x] **Your** code builds clean without any errors or warnings
- [x] Manual testing done (required)
- [ ] Relevant automated test added (if you find this hard, leave it and
we'll help out)

## Documentation

- [ ] Documentation is updated (either in `docs`-directory, Altinnpedia
or a separate linked PR in
[altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if
applicable)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Improved caching strategy for service resource information retrieval,
enhancing performance and efficiency.
- Centralized data fetching logic for service resources, allowing for
more streamlined and efficient access.

- **Bug Fixes**
- Streamlined data fetching logic to minimize unnecessary calls to the
endpoint by utilizing the updated caching mechanism.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
  • Loading branch information
knuhau and oskogstad authored Sep 26, 2024
1 parent 29f0496 commit 8e570b4
Showing 1 changed file with 28 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.Altinn.ResourceRegistry;

internal sealed class ResourceRegistryClient : IResourceRegistry
{
private const string ServiceResourceInformationByOrgCacheKey = "ServiceResourceInformationByOrgCacheKey";
private const string ServiceResourceInformationByResourceIdCacheKey = "ServiceResourceInformationByResourceIdCacheKey";
private const string ServiceResourceInformationCacheKey = "ServiceResourceInformationCacheKey";
private const string ResourceTypeGenericAccess = "GenericAccessResource";
private const string ResourceTypeAltinnApp = "AltinnApp";
private const string ResourceTypeCorrespondence = "CorrespondenceService";
private const string ResourceRegistryResourceEndpoint = "resourceregistry/api/v1/resource/";

private readonly IFusionCache _cache;
private readonly HttpClient _client;
Expand All @@ -26,27 +26,24 @@ public async Task<IReadOnlyCollection<ServiceResourceInformation>> GetResourceIn
string orgNumber,
CancellationToken cancellationToken)
{
var dic = await GetOrSetResourceInformationByOrg(cancellationToken);
if (!dic.TryGetValue(orgNumber, out var resources))
{
resources = [];
}

return resources.AsReadOnly();
var resources = await FetchServiceResourceInformation(cancellationToken);
return resources
.Where(x => x.OwnerOrgNumber == orgNumber)
.ToList();
}

public async Task<ServiceResourceInformation?> GetResourceInformation(
string serviceResourceId,
CancellationToken cancellationToken)
{
var dic = await GetOrSetResourceInformationByResourceId(cancellationToken);
dic.TryGetValue(serviceResourceId, out var resource);
return resource;
var resources = await FetchServiceResourceInformation(cancellationToken);
return resources
.FirstOrDefault(x => x.ResourceId == serviceResourceId);
}

public async IAsyncEnumerable<List<UpdatedSubjectResource>> GetUpdatedSubjectResources(DateTimeOffset since, int batchSize, [EnumeratorCancellation] CancellationToken cancellationToken)
{
const string searchEndpoint = "resourceregistry/api/v1/resource/updated";
const string searchEndpoint = $"{ResourceRegistryResourceEndpoint}updated";
var nextUrl = searchEndpoint + $"?since={Uri.EscapeDataString(since.ToString("O"))}&limit={batchSize}";

do
Expand All @@ -66,56 +63,33 @@ public async IAsyncEnumerable<List<UpdatedSubjectResource>> GetUpdatedSubjectRes
} while (nextUrl is not null);
}


private async Task<Dictionary<string, ServiceResourceInformation[]>> GetOrSetResourceInformationByOrg(
CancellationToken cancellationToken)
private async Task<ServiceResourceInformation[]> FetchServiceResourceInformation(CancellationToken cancellationToken)
{
return await _cache.GetOrSetAsync(
ServiceResourceInformationByOrgCacheKey,
async cToken =>
{
var resources = await FetchServiceResourceInformation(cToken);
return resources
.GroupBy(x => x.OwnerOrgNumber)
.ToDictionary(x => x.Key, x => x.ToArray());
},
token: cancellationToken);
}
const string searchEndpoint = $"{ResourceRegistryResourceEndpoint}resourcelist";

private async Task<Dictionary<string, ServiceResourceInformation>> GetOrSetResourceInformationByResourceId(
CancellationToken cancellationToken)
{
return await _cache.GetOrSetAsync(
ServiceResourceInformationByResourceIdCacheKey,
ServiceResourceInformationCacheKey,
async cToken =>
{
var resources = await FetchServiceResourceInformation(cToken);
return resources.ToDictionary(x => x.ResourceId);
var response = await _client
.GetFromJsonEnsuredAsync<List<ResourceListResponse>>(searchEndpoint,
cancellationToken: cToken);

return response
.Where(x => !string.IsNullOrWhiteSpace(x.HasCompetentAuthority.Organization))
.Where(x => x.ResourceType is
ResourceTypeGenericAccess or
ResourceTypeAltinnApp or
ResourceTypeCorrespondence)
.Select(x => new ServiceResourceInformation(
$"{Constants.ServiceResourcePrefix}{x.Identifier}",
x.ResourceType,
x.HasCompetentAuthority.Organization!))
.ToArray();
},
token: cancellationToken);
}

private async Task<ServiceResourceInformation[]> FetchServiceResourceInformation(CancellationToken cancellationToken)
{
const string searchEndpoint = "resourceregistry/api/v1/resource/resourcelist";

var response = await _client
.GetFromJsonEnsuredAsync<List<ResourceListResponse>>(searchEndpoint,
cancellationToken: cancellationToken);

return response
.Where(x => !string.IsNullOrWhiteSpace(x.HasCompetentAuthority.Organization))
.Where(x => x.ResourceType is
ResourceTypeGenericAccess or
ResourceTypeAltinnApp or
ResourceTypeCorrespondence)
.Select(x => new ServiceResourceInformation(
$"{Constants.ServiceResourcePrefix}{x.Identifier}",
x.ResourceType,
x.HasCompetentAuthority.Organization!))
.ToArray();
}

private sealed class ResourceListResponse
{
public required string Identifier { get; init; }
Expand Down

0 comments on commit 8e570b4

Please sign in to comment.