Skip to content

Commit

Permalink
feat: redis cache (#14158)
Browse files Browse the repository at this point in the history
Co-authored-by: davidovrelid.com <[email protected]>
  • Loading branch information
mirkoSekulic and framitdavid authored Nov 26, 2024
1 parent c47e60f commit c8847c4
Show file tree
Hide file tree
Showing 16 changed files with 84 additions and 25 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ The development environment consist of several services defined in [compose.yaml
- `studio-repos` which is [gitea][14] with some custom config. More [here](gitea/README.md).
- `studio-db` which is a postgres database used by both `studio-designer` and `studio-repos`.
- `database_migrations` which is a one-time task container designed to perform and complete database migrations before exiting.
- `redis` which is a redis cache used by designer.
- `redis-commander` which is a ui for redis cache.

Run all parts of the solution in containers (Make sure docker is running), with docker compose as follows:

Expand Down
3 changes: 2 additions & 1 deletion backend/packagegroups/NuGet.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
<PackageReference Update="Microsoft.Azure.Security.KeyVault.Secrets" Version="4.5.0" />
<PackageReference Update="Microsoft.Azure.Services.AppAuthentication" Version="1.6.2" />
<PackageReference Update="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
<PackageReference Update="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0" />
<PackageReference Update="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0" />
<PackageReference Update="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.0" />
<PackageReference Update="Microsoft.VisualStudio.Web.BrowserLink" Version="2.2.0" />
<PackageReference Update="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Update="HtmlAgilityPack" Version="1.11.67" />
Expand All @@ -40,7 +42,6 @@
<PackageReference Update="DotNetEnv" Version="3.1.1" />
<PackageReference Update="NuGet.Versioning" Version="6.11.1" />
<PackageReference Update="DistributedLock.Postgres" Version="1.2.0" />
<PackageReference Update="Community.Microsoft.Extensions.Caching.PostgreSql" Version="4.0.6" />
</ItemGroup>

<ItemGroup Label="Packages used for testing">
Expand Down
10 changes: 10 additions & 0 deletions backend/src/Designer/Configuration/RedisCacheSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Altinn.Studio.Designer.Configuration.Marker;

namespace Altinn.Studio.Designer.Configuration;

public class RedisCacheSettings : ISettingsMarker
{
public bool UseRedisCache { get; set; } = false;
public string ConnectionString { get; set; }
public string InstanceName { get; set; }
}
3 changes: 2 additions & 1 deletion backend/src/Designer/Designer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
<PackageReference Include="Altinn.Common.AccessTokenClient" />
<PackageReference Include="Altinn.Platform.Storage.Interface" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" />
<PackageReference Include="Community.Microsoft.Extensions.Caching.PostgreSql" />
<PackageReference Include="CompilerAttributes" />
<PackageReference Include="DistributedLock.Postgres" />
<PackageReference Include="DotNetEnv" />
Expand All @@ -38,6 +37,7 @@
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" />
<PackageReference Include="Microsoft.Azure.KeyVault" />
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
Expand All @@ -46,6 +46,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" />
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ public partial class DistributedCacheTable : Migration
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(SqlScriptsReadHelper.ReadSqlScript("DistributedCache/Up/01-setup-distributedcache-table.sql"));
migrationBuilder.Sql(SqlScriptsReadHelper.ReadSqlScript("DistributedCache/Up/02-setup-grants.sql"));
migrationBuilder.Sql(SqlScriptsReadHelper.ReadSqlScript("DistributedCache/Create/01-setup-distributedcache-table.sql"));
migrationBuilder.Sql(SqlScriptsReadHelper.ReadSqlScript("DistributedCache/Create/02-setup-grants.sql"));
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(SqlScriptsReadHelper.ReadSqlScript("DistributedCache/Down/01-drop-distributedcache-table.sql"));
migrationBuilder.Sql(SqlScriptsReadHelper.ReadSqlScript("DistributedCache/Drop/01-drop-distributedcache-table.sql"));
}
}
}
24 changes: 10 additions & 14 deletions backend/src/Designer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using Altinn.Studio.Designer.Services.Interfaces;
using Altinn.Studio.Designer.Tracing;
using Altinn.Studio.Designer.TypedHttpClients;
using Community.Microsoft.Extensions.Caching.PostgreSql;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.EventCounterCollector;
using Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -204,7 +203,6 @@ void ConfigureServices(IServiceCollection services, IConfiguration configuration
services.AddMemoryCache();
services.AddResponseCompression();
services.AddHealthChecks().AddCheck<HealthCheck>("designer_health_check");
services.AddSignalR();

CreateDirectory(configuration);

Expand Down Expand Up @@ -253,19 +251,17 @@ void ConfigureServices(IServiceCollection services, IConfiguration configuration
services.AddFeatureManagement();
services.RegisterSynchronizationServices(configuration);

// Override the default distributed cache with a PostgreSQL implementation
services.AddDistributedPostgreSqlCache(setup =>
var signalRBuilder = services.AddSignalR();
var redisSettings = configuration.GetSection(nameof(RedisCacheSettings)).Get<RedisCacheSettings>();
if (redisSettings.UseRedisCache)
{
PostgreSQLSettings postgresSettings =
configuration.GetSection(nameof(PostgreSQLSettings)).Get<PostgreSQLSettings>();

setup.ConnectionString = postgresSettings.FormattedConnectionString();
setup.SchemaName = "designer";
setup.TableName = "distributedcache";
setup.DisableRemoveExpired = false;
setup.CreateInfrastructure = false;
setup.ExpiredItemsDeletionInterval = TimeSpan.FromMinutes(30);
});
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisSettings.ConnectionString;
options.InstanceName = redisSettings.InstanceName;
});
signalRBuilder.AddStackExchangeRedis(redisSettings.ConnectionString);
}

if (!env.IsDevelopment())
{
Expand Down
3 changes: 3 additions & 0 deletions backend/src/Designer/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,8 @@
"SlackSettings": {
"WebhookUrl": "https://hooks.slack.com/services/"
}
},
"RedisCacheSettings": {
"UseRedisCache": false
}
}
12 changes: 12 additions & 0 deletions charts/altinn-designer/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ environmentVariables:
value: "true"
- name: FeatureManagement__EidLogging
value: "true"
- name: RedisCacheSettings__UseRedisCache
value: "true"
- name: RedisCacheSettings__InstanceName
value: "designer"
staging:
- name: ASPNETCORE_ENVIRONMENT
value: Staging
Expand Down Expand Up @@ -91,6 +95,10 @@ environmentVariables:
value: "false"
- name: FeatureManagement__EidLogging
value: "true"
- name: RedisCacheSettings__UseRedisCache
value: "true"
- name: RedisCacheSettings__InstanceName
value: "designer"
prod:
- name: ASPNETCORE_ENVIRONMENT
value: Production
Expand Down Expand Up @@ -124,6 +132,10 @@ environmentVariables:
value: "false"
- name: FeatureManagement__EidLogging
value: "true"
- name: RedisCacheSettings__UseRedisCache
value: "true"
- name: RedisCacheSettings__InstanceName
value: "designer"

dbMigrationsEnvironmentVariablesSecretName: altinn-designer-db-migrations-secret

Expand Down
23 changes: 23 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ volumes:
gitea-attachments-data:
keys:
pgdata:
redisdata:

services:
studio_azure_mock:
Expand Down Expand Up @@ -87,6 +88,9 @@ services:
- FeatureManagement:Ansattporten=${FEATUREFLAGS_ANSATTPORTEN:-false}
- AnsattPortenLoginSettings:ClientId=${ANSATTPORTEN_CLIENTID:-}
- AnsattPortenLoginSettings:ClientSecret=${ANSATTPORTEN_CLIENTSECRET:-}
- RedisCacheSettings:UseRedisCache=true
- RedisCacheSettings:ConnectionString=redis:6379
- RedisCacheSettings:InstanceName=designer

ports:
- '6000:6000'
Expand Down Expand Up @@ -184,3 +188,22 @@ services:
- PGUSER=designer_admin
- PGPASSWORD=${POSTGRES_PASSWORD}
- PGDATABASE=designerdb

redis:
image: redis:alpine
container_name: redis
restart: always
command: redis-server --save 60 1 --loglevel warning
ports:
- "6379:6379"
volumes:
- redisdata:/data

redis-commander:
container_name: redis-commander
image: rediscommander/redis-commander:latest
restart: always
environment:
- REDIS_HOSTS=redis
ports:
- "8081:8081"
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ReactNode } from 'react';
import React, { createContext, useContext, useEffect, useState } from 'react';
import { previewSignalRHubSubPath } from 'app-shared/api/paths';
import type { HubConnection } from '@microsoft/signalr';
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
import { HttpTransportType, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';

const PreviewConnectionContext = createContext<HubConnection>(null);

Expand All @@ -17,7 +17,10 @@ export const PreviewConnectionContextProvider = ({

useEffect(() => {
const newConnection = new HubConnectionBuilder()
.withUrl(previewSignalRHubSubPath())
.withUrl(previewSignalRHubSubPath(), {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
})
.configureLogging(LogLevel.Information)
.build();
setConnection(newConnection);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { WSConnector } from 'app-shared/websockets/WSConnector';

jest.mock('@microsoft/signalr', () => ({
...jest.requireActual('@microsoft/signalr'),
HubConnection: jest.fn().mockReturnValue({
start: jest.fn().mockResolvedValue('started'),
}),
Expand Down
7 changes: 5 additions & 2 deletions frontend/packages/shared/src/websockets/WSConnector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
import { HttpTransportType, type HubConnection, HubConnectionBuilder } from '@microsoft/signalr';

export class WSConnector {
private connection: HubConnection;
Expand Down Expand Up @@ -30,7 +30,10 @@ export class WSConnector {

private createConnection(webSocketUrl: string): void {
this.connection = new HubConnectionBuilder()
.withUrl(webSocketUrl)
.withUrl(webSocketUrl, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
})
.withAutomaticReconnect()
.build();
}
Expand Down
8 changes: 6 additions & 2 deletions frontend/testing/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ResizeObserver {
unobserve = jest.fn();
disconnect = jest.fn();
}

window.ResizeObserver = ResizeObserver;

// document.getAnimations must be mocked because it is used by the design system, but it is not supported by React Testing Library.
Expand Down Expand Up @@ -77,8 +78,11 @@ jest.mock('react-i18next', () => ({
},
}));

// SignalR PreviewHub mock to simulate setup of websockets.
jest.mock('@microsoft/signalr', () => SignalR);
// Mocked SignalR to be able to test in within the tests.
jest.mock('@microsoft/signalr', () => ({
...jest.requireActual('@microsoft/signalr'),
...SignalR,
}));

// Mock org and app params
jest.mock('react-router-dom', () => ({
Expand Down

0 comments on commit c8847c4

Please sign in to comment.