Skip to content

Commit

Permalink
feat: add snapshot on request
Browse files Browse the repository at this point in the history
  • Loading branch information
jvandaal authored and ArneD committed Jan 3, 2025
1 parent 2a8ea03 commit 2636902
Show file tree
Hide file tree
Showing 25 changed files with 688 additions and 94 deletions.
22 changes: 11 additions & 11 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ nuget CsvHelper 33.0.1
nuget Be.Vlaanderen.Basisregisters.Build.Pipeline 7.2.5
nuget Be.Vlaanderen.Basisregisters.Testing.Infrastructure.Events 4.0.0 content: true, copy_content_to_output_dir: always, copy_local: true

nuget Be.Vlaanderen.Basisregisters.AggregateSource 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.ExplicitRouting 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing.CommandHandling 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore.Autofac 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing.Xunit 9.0.1
nuget Be.vlaanderen.basisregisters.SnapshotVerifier 9.0.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource 9.1.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.ExplicitRouting 9.1.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac 9.1.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing 9.1.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing.CommandHandling 9.1.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore.Autofac 9.1.1
nuget Be.Vlaanderen.Basisregisters.AggregateSource.Testing.Xunit 9.1.1
nuget Be.vlaanderen.basisregisters.SnapshotVerifier 9.1.1

nuget Be.Vlaanderen.Basisregisters.Api 23.1.0

Expand All @@ -54,9 +54,9 @@ nuget Be.Vlaanderen.Basisregisters.Auth.AcmIdm 3.3.0
nuget Be.Vlaanderen.Basisregisters.Aws.DistributedMutex 4.0.1
nuget Be.Vlaanderen.Basisregisters.Aws.Lambda 4.0.0

nuget Be.Vlaanderen.Basisregisters.CommandHandling 9.0.1
nuget Be.Vlaanderen.Basisregisters.CommandHandling.Idempotency 9.0.1
nuget Be.Vlaanderen.Basisregisters.CommandHandling.SqlStreamStore 9.0.1
nuget Be.Vlaanderen.Basisregisters.CommandHandling 9.1.1
nuget Be.Vlaanderen.Basisregisters.CommandHandling.Idempotency 9.1.1
nuget Be.Vlaanderen.Basisregisters.CommandHandling.SqlStreamStore 9.1.1

nuget Be.Vlaanderen.Basisregisters.EventHandling 6.0.0
nuget Be.Vlaanderen.Basisregisters.EventHandling.Autofac 6.0.0
Expand Down
60 changes: 30 additions & 30 deletions paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -61,44 +61,44 @@ NUGET
System.Security.Cryptography.ProtectedData (>= 4.7)
System.Text.Json (>= 4.7.2)
System.Threading.Tasks.Extensions (>= 4.5.4)
Be.Vlaanderen.Basisregisters.AggregateSource (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.1.1)
Be.Vlaanderen.Basisregisters.Utilities.HashCodeCalculator (>= 4.0)
Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor (>= 4.0)
Be.Vlaanderen.Basisregisters.Utilities.ToStringBuilder (>= 4.0)
Newtonsoft.Json (>= 13.0.3)
NodaTime (>= 3.1.11)
Be.Vlaanderen.Basisregisters.AggregateSource.ExplicitRouting (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.ExplicitRouting (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.1.1)
Be.Vlaanderen.Basisregisters.EventHandling (>= 5.0)
SqlStreamStore (>= 1.2)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac (9.1.1)
Autofac.Extensions.DependencyInjection (>= 9.0)
Be.Vlaanderen.Basisregisters.AggregateSource (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (9.1.1)
SqlStreamStore (>= 1.2)
SqlStreamStore.MsSql (>= 1.2)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.1.1)
CompareNETObjects (>= 4.83)
Microsoft.CSharp (>= 4.7)
Newtonsoft.Json (>= 13.0.3)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.CommandHandling (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.0.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.CommandHandling (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.1.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.1.1)
Be.Vlaanderen.Basisregisters.EventHandling (>= 5.0)
SqlStreamStore (>= 1.2)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore.Autofac (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore.Autofac (9.1.1)
Autofac.Extensions.DependencyInjection (>= 9.0)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.CommandHandling (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.Xunit (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.Xunit (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.CommandHandling (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.SqlStreamStore (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.Xunit (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing.Xunit (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.Testing (9.1.1)
Microsoft.Extensions.Logging (>= 8.0)
xunit (>= 2.7)
Be.Vlaanderen.Basisregisters.Api (23.1)
Expand Down Expand Up @@ -218,19 +218,19 @@ NUGET
Microsoft.Extensions.DependencyInjection (>= 8.0)
Microsoft.Extensions.Logging (>= 8.0)
Be.Vlaanderen.Basisregisters.Build.Pipeline (7.2.5)
Be.Vlaanderen.Basisregisters.CommandHandling (9.0.1)
Be.Vlaanderen.Basisregisters.CommandHandling.Idempotency (9.0.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.0.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.1.1)
Be.Vlaanderen.Basisregisters.CommandHandling.Idempotency (9.1.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.1.1)
Be.Vlaanderen.Basisregisters.Converters.Timestamp (>= 4.0)
Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor (>= 4.0)
Microsoft.Data.SqlClient (>= 5.2)
Microsoft.EntityFrameworkCore.SqlServer (>= 8.0.2)
Microsoft.Extensions.Configuration (>= 8.0)
Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0)
Newtonsoft.Json (>= 13.0.3)
Be.Vlaanderen.Basisregisters.CommandHandling.SqlStreamStore (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.0.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.0.1)
Be.Vlaanderen.Basisregisters.CommandHandling.SqlStreamStore (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource (9.1.1)
Be.Vlaanderen.Basisregisters.CommandHandling (9.1.1)
Be.Vlaanderen.Basisregisters.EventHandling (>= 5.0)
Be.Vlaanderen.Basisregisters.Generators.Guid.Deterministic (>= 4.0)
SqlStreamStore (>= 1.2)
Expand Down Expand Up @@ -396,8 +396,8 @@ NUGET
System.Configuration.ConfigurationManager (>= 8.0)
System.Threading.Tasks.Dataflow (>= 8.0)
Be.Vlaanderen.Basisregisters.Shaperon (10.0.2)
Be.Vlaanderen.Basisregisters.SnapshotVerifier (9.0.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (9.0.1)
Be.Vlaanderen.Basisregisters.SnapshotVerifier (9.1.1)
Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (9.1.1)
CompareNETObjects (>= 4.83)
Dapper (>= 2.1.35)
Microsoft.Extensions.Hosting (>= 8.0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace AddressRegistry.Api.BackOffice.Abstractions.Requests
{
using System.Runtime.Serialization;
using Newtonsoft.Json;

[DataContract(Name = "SnapshotStraatnaam", Namespace = "")]
public sealed class CreateStreetNameSnapshotRequest
{
/// <summary>
/// De unieke en persistente identificator van de straatnaam.
/// </summary>
[DataMember(Name = "StreetNamePersistentLocalId", Order = 0)]
[JsonProperty(Required = Required.Always)]
public int StreetNamePersistentLocalId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace AddressRegistry.Api.BackOffice.Abstractions.SqsRequests
{
using Be.Vlaanderen.Basisregisters.Sqs.Requests;
using Requests;

public sealed class CreateStreetNameSnapshotSqsRequest : SqsRequest
{
public CreateStreetNameSnapshotRequest Request { get; init; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace AddressRegistry.Api.BackOffice.Handlers.Lambda.Handlers
{
using Be.Vlaanderen.Basisregisters.AggregateSource;
using Be.Vlaanderen.Basisregisters.CommandHandling.Idempotency;
using Be.Vlaanderen.Basisregisters.Sqs.Lambda.Infrastructure;
using Microsoft.Extensions.Configuration;
using Requests;
using StreetName;
using TicketingService.Abstractions;

public sealed class CreateStreetNameSnapshotLambdaHandler : SqsLambdaHandler<CreateStreetNameSnapshotLambdaRequest>
{
public CreateStreetNameSnapshotLambdaHandler(
IConfiguration configuration,
ICustomRetryPolicy retryPolicy,
ITicketing ticketing,
IStreetNames streetNames,
IIdempotentCommandHandler idempotentCommandHandler)
: base(
configuration,
retryPolicy,
streetNames,
ticketing,
idempotentCommandHandler)
{ }

protected override async Task<object> InnerHandle(CreateStreetNameSnapshotLambdaRequest request, CancellationToken cancellationToken)
{
var cmd = request.ToCommand();

try
{
await IdempotentCommandHandler.Dispatch(
cmd.CreateCommandId(),
cmd,
request.Metadata!,
cancellationToken);
}
catch (IdempotencyException)
{
// Idempotent: Do Nothing return last etag
}

return "snapshot created";
}

protected override TicketError? InnerMapDomainException(DomainException exception, CreateStreetNameSnapshotLambdaRequest request)
{
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public async Task HandleMessage(object? messageData, MessageMetadata messageMeta
case ReaddressSqsRequest request:
await mediator.Send(new ReaddressLambdaRequest(messageMetadata.MessageGroupId!, request), cancellationToken);
break;
case CreateStreetNameSnapshotSqsRequest request:
await mediator.Send(new CreateStreetNameSnapshotLambdaRequest(messageMetadata.MessageGroupId!, request), cancellationToken);
break;
default:
throw new NotImplementedException(
$"{sqsRequest.GetType().Name} has no corresponding SqsLambdaRequest defined.");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace AddressRegistry.Api.BackOffice.Handlers.Lambda.Requests
{
using Abstractions.Requests;
using Abstractions.SqsRequests;
using Be.Vlaanderen.Basisregisters.Sqs.Lambda.Requests;
using StreetName;
using StreetName.Commands;

public sealed record CreateStreetNameSnapshotLambdaRequest :
SqsLambdaRequest,
IHasBackOfficeRequest<CreateStreetNameSnapshotRequest>
{
public CreateStreetNameSnapshotRequest Request { get; init; }

public CreateStreetNameSnapshotLambdaRequest(
string messageGroupId,
CreateStreetNameSnapshotSqsRequest sqsRequest)
: base(
messageGroupId,
sqsRequest.TicketId,
null,
sqsRequest.ProvenanceData.ToProvenance(),
sqsRequest.Metadata)
{
Request = sqsRequest.Request;
}

/// <summary>
/// Map to CreateSnapshot command.
/// </summary>
/// <returns>CreateSnapshot</returns>
public CreateSnapshot ToCommand()
{
return new CreateSnapshot(
new StreetNamePersistentLocalId(Request.StreetNamePersistentLocalId),
Provenance);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
namespace AddressRegistry.Api.BackOffice
{
using System.Threading;
using System.Threading.Tasks;
using Abstractions.Requests;
using Abstractions.SqsRequests;
using Abstractions.Validation;
using Be.Vlaanderen.Basisregisters.Api.Exceptions;
using Be.Vlaanderen.Basisregisters.Auth.AcmIdm;
using Be.Vlaanderen.Basisregisters.GrAr.Provenance;
using Be.Vlaanderen.Basisregisters.Sqs.Exceptions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Filters;

public partial class AddressController
{
/// <summary>
/// Snapshot voor de straatnaam aanvragen.
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <response code="202">Als de snapshot voor de straatnaam aangevraagd is.</response>
/// <returns></returns>
[HttpPost("acties/snapshot")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
[SwaggerResponseExample(StatusCodes.Status400BadRequest, typeof(BadRequestResponseExamples))]
[SwaggerResponseExample(StatusCodes.Status500InternalServerError, typeof(InternalServerErrorResponseExamples))]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = PolicyNames.Adres.InterneBijwerker)]
public async Task<IActionResult> CreateSnapshot(
[FromBody] CreateStreetNameSnapshotRequest request,
CancellationToken cancellationToken = default)
{
try
{
var sqsRequest = new CreateStreetNameSnapshotSqsRequest
{
Request = request,
Metadata = GetMetadata(),
ProvenanceData = new ProvenanceData(CreateProvenance(Modification.Unknown)),
};

var sqsResult = await _mediator.Send(sqsRequest, cancellationToken);

return Accepted(sqsResult);
}
catch (AggregateIdIsNotFoundException)
{
throw new ApiException(ValidationErrors.Common.AddressNotFound.Message, StatusCodes.Status404NotFound);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace AddressRegistry.Api.BackOffice.Handlers
{
using System.Collections.Generic;
using System.Linq;
using Abstractions;
using Abstractions.SqsRequests;
using Be.Vlaanderen.Basisregisters.Sqs;
using Be.Vlaanderen.Basisregisters.Sqs.Handlers;
using TicketingService.Abstractions;

public sealed class CreateStreetNameSnapshotSqsHandler : SqsHandler<CreateStreetNameSnapshotSqsRequest>
{
public const string Action = "CreateStreetNameSnapshot";

private readonly BackOfficeContext _backOfficeContext;

public CreateStreetNameSnapshotSqsHandler(
ISqsQueue sqsQueue,
ITicketing ticketing,
ITicketingUrl ticketingUrl,
BackOfficeContext backOfficeContext)
: base(sqsQueue, ticketing, ticketingUrl)
{
_backOfficeContext = backOfficeContext;
}

protected override string? WithAggregateId(CreateStreetNameSnapshotSqsRequest request)
{
return _backOfficeContext
.AddressPersistentIdStreetNamePersistentIds
.SingleOrDefault(x => x.StreetNamePersistentLocalId == request.Request.StreetNamePersistentLocalId)
?.StreetNamePersistentLocalId.ToString();
}

protected override IDictionary<string, string> WithTicketMetadata(string aggregateId, CreateStreetNameSnapshotSqsRequest sqsRequest)
{
return new Dictionary<string, string>
{
{ RegistryKey, nameof(AddressRegistry) },
{ ActionKey, Action },
{ AggregateIdKey, aggregateId }
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace AddressRegistry.Infrastructure.Modules
using Be.Vlaanderen.Basisregisters.EventHandling.Autofac;
using Microsoft.Extensions.Configuration;
using StreetName;
using StreetName.Events;

public class AggregateSourceModule : Module
{
Expand All @@ -30,8 +31,10 @@ protected override void Load(ContainerBuilder builder)
snapshotStrategy = IntervalStrategy.SnapshotEvery(snapshotInterval);
}

var anySnapshot = new AnySnapshotStrategy([snapshotStrategy, new AfterEventTypeStrategy(typeof(StreetNameSnapshotWasRequested))]);

builder
.Register(c => new StreetNameFactory(snapshotStrategy))
.Register(c => new StreetNameFactory(anySnapshot))
.As<IStreetNameFactory>();

builder
Expand Down
Loading

0 comments on commit 2636902

Please sign in to comment.