Skip to content

Commit

Permalink
refac: Improve model for Process Manager (Http) (#1391)
Browse files Browse the repository at this point in the history
* Use FromBodyAttribute from Microsoft.Azure.Functions.Worker.Http namespace

* Use ComplexProperty where possible

* Implement OrchestrationDescriptionUniqueName and refactor accordingly

* OrchestrationDescriptionUniqueNameDto

* Delete dto
  • Loading branch information
dstenroejl authored Nov 26, 2024
1 parent 8587c3a commit 20c5bd8
Show file tree
Hide file tree
Showing 19 changed files with 183 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ public async Task Given_UserCanceledOrchestrationInstanceAddedToDbContext_WhenRe
private static OrchestrationDescription CreateOrchestrationDescription()
{
var orchestrationDescription = new OrchestrationDescription(
name: "TestOrchestration",
version: 4,
uniqueName: new OrchestrationDescriptionUniqueName("TestOrchestration", 4),
canBeScheduled: true,
functionName: "TestOrchestrationFunction");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,12 @@ public async Task GivenScheduledOrchestrationInstancesInDatabase_WhenGetSchedule
public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByName_ThenExpectedOrchestrationInstancesAreRetrieved()
{
// Arrange
var uniqueName1 = Guid.NewGuid().ToString();
var existingOrchestrationDescription01 = CreateOrchestrationDescription(uniqueName1, version: 1);
var uniqueName1 = new OrchestrationDescriptionUniqueName(Guid.NewGuid().ToString(), 1);
var existingOrchestrationDescription01 = CreateOrchestrationDescription(uniqueName1);
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescription01);

var uniqueName2 = Guid.NewGuid().ToString();
var existingOrchestrationDescription02 = CreateOrchestrationDescription(uniqueName2, version: 1);
var uniqueName2 = new OrchestrationDescriptionUniqueName(Guid.NewGuid().ToString(), 1);
var existingOrchestrationDescription02 = CreateOrchestrationDescription(uniqueName2);
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescription02);

var basedOn01 = CreateOrchestrationInstance(existingOrchestrationDescription01);
Expand All @@ -178,7 +178,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByName_ThenExp
await _sut.UnitOfWork.CommitAsync();

// Act
var actual = await _sut.SearchAsync(existingOrchestrationDescription01.Name);
var actual = await _sut.SearchAsync(existingOrchestrationDescription01.UniqueName.Name);

// Assert
actual.Should()
Expand All @@ -189,11 +189,11 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByName_ThenExp
public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndVersion_ThenExpectedOrchestrationInstancesAreRetrieved()
{
// Arrange
var uniqueName = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1);
var name = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1);

var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(uniqueName, version: 2);
var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 2));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV2);

var basedOnV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1);
Expand All @@ -205,7 +205,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndVersi
await _sut.UnitOfWork.CommitAsync();

// Act
var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.Name, existingOrchestrationDescriptionV1.Version);
var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.UniqueName.Name, existingOrchestrationDescriptionV1.UniqueName.Version);

// Assert
actual.Should()
Expand All @@ -216,11 +216,11 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndVersi
public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndLifecycleState_ThenExpectedOrchestrationInstancesAreRetrieved()
{
// Arrange
var uniqueName = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1);
var name = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1);

var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(uniqueName, version: 2);
var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 2));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV2);

var isPendingV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1);
Expand All @@ -242,7 +242,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndLifec
await _sut.UnitOfWork.CommitAsync();

// Act
var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.Name, lifecycleState: OrchestrationInstanceLifecycleStates.Running);
var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.UniqueName.Name, lifecycleState: OrchestrationInstanceLifecycleStates.Running);

// Assert
actual.Should()
Expand All @@ -253,11 +253,11 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndLifec
public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTerminationState_ThenExpectedOrchestrationInstancesAreRetrieved()
{
// Arrange
var uniqueName = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1);
var name = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1);

var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(uniqueName, version: 2);
var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 2));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV2);

var isPendingV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1);
Expand All @@ -282,7 +282,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi

// Act
var actual = await _sut.SearchAsync(
existingOrchestrationDescriptionV1.Name,
existingOrchestrationDescriptionV1.UniqueName.Name,
lifecycleState: OrchestrationInstanceLifecycleStates.Terminated,
terminationState: OrchestrationInstanceTerminationStates.Succeeded);

Expand All @@ -300,8 +300,8 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndStart
startedAtClockMock01.Setup(m => m.GetCurrentInstant())
.Returns(startedAt01);

var uniqueName = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1);
var name = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1);

var isPending = CreateOrchestrationInstance(existingOrchestrationDescriptionV1);
Expand All @@ -321,7 +321,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndStart

// Act
var actual = await _sut.SearchAsync(
existingOrchestrationDescriptionV1.Name,
existingOrchestrationDescriptionV1.UniqueName.Name,
startedAtOrLater: startedAt01);

// Assert
Expand All @@ -338,8 +338,8 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi
terminatedAtClockMock01.Setup(m => m.GetCurrentInstant())
.Returns(terminatedAt01);

var uniqueName = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1);
var name = Guid.NewGuid().ToString();
var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1));
await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1);

var isPending = CreateOrchestrationInstance(existingOrchestrationDescriptionV1);
Expand All @@ -366,19 +366,18 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi

// Act
var actual = await _sut.SearchAsync(
existingOrchestrationDescriptionV1.Name,
existingOrchestrationDescriptionV1.UniqueName.Name,
terminatedAtOrEarlier: terminatedAt01);

// Assert
actual.Should()
.BeEquivalentTo(new[] { isTerminated01 });
}

private static OrchestrationDescription CreateOrchestrationDescription(string? name = default, int? version = default)
private static OrchestrationDescription CreateOrchestrationDescription(OrchestrationDescriptionUniqueName? uniqueName = default)
{
var orchestrationDescription = new OrchestrationDescription(
name: name ?? "TestOrchestration",
version: version ?? 4,
uniqueName: uniqueName ?? new OrchestrationDescriptionUniqueName("TestOrchestration", 4),
canBeScheduled: true,
functionName: "TestOrchestrationFunction");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ internal interface IOrchestrationRegisterQueries
{
Task<OrchestrationDescription> GetAsync(OrchestrationDescriptionId id);

Task<OrchestrationDescription?> GetOrDefaultAsync(string name, int version, bool? isEnabled);
Task<OrchestrationDescription?> GetOrDefaultAsync(OrchestrationDescriptionUniqueName uniqueName, bool? isEnabled);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription;
using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance;
using NodaTime;

Expand All @@ -24,8 +25,7 @@ public interface IStartOrchestrationInstanceCommands
/// </summary>
Task<OrchestrationInstanceId> StartNewOrchestrationInstanceAsync<TParameter>(
OperatingIdentity identity,
string name,
int version,
OrchestrationDescriptionUniqueName uniqueName,
TParameter inputParameter,
IReadOnlyCollection<int> skipStepsBySequence)
where TParameter : class;
Expand All @@ -35,8 +35,7 @@ Task<OrchestrationInstanceId> StartNewOrchestrationInstanceAsync<TParameter>(
/// </summary>
Task<OrchestrationInstanceId> ScheduleNewOrchestrationInstanceAsync<TParameter>(
UserIdentity identity,
string name,
int version,
OrchestrationDescriptionUniqueName uniqueName,
TParameter inputParameter,
Instant runAt,
IReadOnlyCollection<int> skipStepsBySequence)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,13 @@ internal class OrchestrationInstanceManager(
/// <inheritdoc />
public async Task<OrchestrationInstanceId> StartNewOrchestrationInstanceAsync<TParameter>(
OperatingIdentity identity,
string name,
int version,
OrchestrationDescriptionUniqueName uniqueName,
TParameter inputParameter,
IReadOnlyCollection<int> skipStepsBySequence)
where TParameter : class
{
var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync(
name,
version,
uniqueName,
inputParameter,
skipStepsBySequence).ConfigureAwait(false);

Expand All @@ -68,16 +66,14 @@ await RequestStartOfOrchestrationInstanceAsync(
/// <inheritdoc />
public async Task<OrchestrationInstanceId> ScheduleNewOrchestrationInstanceAsync<TParameter>(
UserIdentity userIdentity,
string name,
int version,
OrchestrationDescriptionUniqueName uniqueName,
TParameter inputParameter,
Instant runAt,
IReadOnlyCollection<int> skipStepsBySequence)
where TParameter : class
{
var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync(
name,
version,
uniqueName,
inputParameter,
skipStepsBySequence).ConfigureAwait(false);

Expand Down Expand Up @@ -124,15 +120,14 @@ public async Task CancelScheduledOrchestrationInstanceAsync(UserIdentity userIde
/// Validate orchestration description is known and that paramter value is valid according to its parameter definition.
/// </summary>
private async Task<OrchestrationDescription> GuardMatchingOrchestrationDescriptionAsync<TParameter>(
string name,
int version,
OrchestrationDescriptionUniqueName uniqueName,
TParameter inputParameter,
IReadOnlyCollection<int> skipStepsBySequence)
where TParameter : class
{
var orchestrationDescription = await _orchestrationRegister.GetOrDefaultAsync(name, version, isEnabled: true).ConfigureAwait(false);
var orchestrationDescription = await _orchestrationRegister.GetOrDefaultAsync(uniqueName, isEnabled: true).ConfigureAwait(false);
if (orchestrationDescription == null)
throw new InvalidOperationException($"No enabled orchestration description matches Name='{name}' and Version='{version}'.");
throw new InvalidOperationException($"No enabled orchestration description matches UniqueName='{uniqueName}'.");

var isValidParameterValue = await orchestrationDescription.ParameterDefinition.IsValidParameterValueAsync(inputParameter).ConfigureAwait(false);
if (isValidParameterValue == false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ public static async Task SynchronizeAsync(
{
var hostDescription = hostDescriptions
.SingleOrDefault(x =>
x.Name == registerDescription.Name
&& x.Version == registerDescription.Version);
x.UniqueName == registerDescription.UniqueName);

if (hostDescription == null)
await register.DeregisterAsync(registerDescription).ConfigureAwait(false);
Expand All @@ -54,8 +53,7 @@ public static async Task SynchronizeAsync(
{
var registerDescription = registerDescriptions
.SingleOrDefault(x =>
x.Name == hostDescription.Name
&& x.Version == hostDescription.Version);
x.UniqueName == hostDescription.UniqueName);

if (registerDescription == null || registerDescription.IsEnabled == false)
await register.RegisterAsync(hostDescription, hostName).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ public class OrchestrationDescription
private readonly List<StepDescription> _steps;

public OrchestrationDescription(
string name,
int version,
OrchestrationDescriptionUniqueName uniqueName,
bool canBeScheduled,
string functionName)
{
Id = new OrchestrationDescriptionId(Guid.NewGuid());
Name = name;
Version = version;
UniqueName = uniqueName;
CanBeScheduled = canBeScheduled;
FunctionName = functionName;
ParameterDefinition = new();
Expand All @@ -55,14 +53,9 @@ private OrchestrationDescription()
public OrchestrationDescriptionId Id { get; }

/// <summary>
/// A name which combined with the <see cref="Version"/> uniquely identifies the orchestration.
/// Uniquely identifies a specific implementation of the orchestration.
/// </summary>
public string Name { get; }

/// <summary>
/// A version which combined with the <see cref="Name"/> uniquely identifies the orchestration.
/// </summary>
public int Version { get; }
public OrchestrationDescriptionUniqueName UniqueName { get; }

/// <summary>
/// Specifies if the orchestration supports scheduling.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@

namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription;

public record OrchestrationDescriptionId(Guid Value);
public record OrchestrationDescriptionId
{
internal OrchestrationDescriptionId(Guid value)
{
Value = value;
}

public Guid Value { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription;

/// <summary>
/// Uniquely identifies a specific implementation of the orchestration.
/// </summary>
public record OrchestrationDescriptionUniqueName
{
/// <summary>
/// Access modifier is set so we nudge consumers from outside Proces Manager to
/// inherit from the record and hopefully create specific implementations per
/// orchestration so we get kind of "named" orchestrations modelled in records.
/// We allow internal use to support easy testing where we then don't have to
/// implement specifci "named" orchestrations.
/// </summary>
protected internal OrchestrationDescriptionUniqueName(string name, int version)
{
// Explicit guard for empty string
ArgumentException.ThrowIfNullOrWhiteSpace(name);

Name = name;
Version = version;
}

/// <summary>
/// A common name to identity the orchestration.
/// </summary>
public string Name { get; }

/// <summary>
/// A version identifying a specific implementation of the orchestration.
/// </summary>
public int Version { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,20 @@ public void Configure(EntityTypeBuilder<OrchestrationDescription> builder)
id => id.Value,
dbValue => new OrchestrationDescriptionId(dbValue));

builder.Property(o => o.Name);
builder.Property(o => o.Version);
builder.ComplexProperty(
o => o.UniqueName,
b =>
{
b.Property(un => un.Name)
.HasColumnName(nameof(OrchestrationDescriptionUniqueName.Name));
b.Property(un => un.Version)
.HasColumnName(nameof(OrchestrationDescriptionUniqueName.Version));
});

builder.Property(o => o.CanBeScheduled);
builder.Property(o => o.FunctionName);

builder.OwnsOne(
builder.ComplexProperty(
o => o.ParameterDefinition,
b =>
{
Expand Down
Loading

0 comments on commit 20c5bd8

Please sign in to comment.