Skip to content

Commit

Permalink
feat: Auto register handlers (#57)
Browse files Browse the repository at this point in the history
* IOrchestrationDescriptionBuilder

* Start/schedule handlers

* Namespace

* Fix naming and design

* TODO's

* Interface for query handler

* Refactor example

* Avoid changning NuGet packages
  • Loading branch information
dstenroejl authored Dec 27, 2024
1 parent 8be8819 commit d6cad01
Show file tree
Hide file tree
Showing 27 changed files with 224 additions and 134 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

using Energinet.DataHub.ProcessManager.Abstractions.Api.Model;

namespace Energinet.DataHub.ProcessManagement.Core.Application.Api.Handlers;

/// <summary>
/// Interface for handling a command for scheduling an orchestration instance with an input parameter.
/// </summary>
/// <typeparam name="TCommand">The type of the command.</typeparam>
/// <typeparam name="TInputParameterDto">The type of the input parameter DTO.</typeparam>
public interface IScheduleOrchestrationInstanceCommandHandler<TCommand, TInputParameterDto>
where TCommand : ScheduleOrchestrationInstanceCommand<TInputParameterDto>
where TInputParameterDto : IInputParameterDto
{
/// <summary>
/// Handles a command for scheduling an orchestration instance.
/// </summary>
/// <param name="command">The command to handle.</param>
/// <returns>The ID of the orchestration instance.</returns>
Task<Guid> HandleAsync(TCommand command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

using Energinet.DataHub.ProcessManager.Abstractions.Api.Model;

namespace Energinet.DataHub.ProcessManagement.Core.Application.Api.Handlers;

/// <summary>
/// Interface for handling a query for searching orchestration instances.
/// </summary>
/// <typeparam name="TQuery">The type of the query.</typeparam>
/// <typeparam name="TResultItem">The result type of each item returned in the result list from the query. Must be a JSON serializable type.</typeparam>
public interface ISearchOrchestrationInstancesQueryHandler<TQuery, TResultItem>
where TQuery : SearchOrchestrationInstancesByCustomQuery<TResultItem>
where TResultItem : class
{
/// <summary>
/// Handles a query for searching orchestration instances.
/// </summary>
/// <param name="query">The query to handle.</param>
/// <returns>Returns a result item for each matching orchestration instance.</returns>
Task<IReadOnlyCollection<TResultItem>> HandleAsync(TQuery query);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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.

using Energinet.DataHub.ProcessManager.Abstractions.Api.Model;
using Energinet.DataHub.ProcessManager.Abstractions.Api.Model.OrchestrationInstance;

namespace Energinet.DataHub.ProcessManagement.Core.Application.Api.Handlers;

/// <summary>
/// Interface for handling a command for starting an orchestration instance with an input parameter.
/// </summary>
/// <typeparam name="TCommand">The type of the command.</typeparam>
/// <typeparam name="TInputParameterDto">The type of the input parameter DTO.</typeparam>
public interface IStartOrchestrationInstanceCommandHandler<TCommand, TInputParameterDto>
where TCommand : StartOrchestrationInstanceCommand<UserIdentityDto, TInputParameterDto>
where TInputParameterDto : IInputParameterDto
{
/// <summary>
/// Handles a command for starting an orchestration instance.
/// </summary>
/// <param name="command">The command to handle.</param>
/// <returns>The ID of the orchestration instance.</returns>
Task<Guid> HandleAsync(TCommand command);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
using Energinet.DataHub.ProcessManager.Abstractions.Contracts;
using Microsoft.Extensions.Logging;

namespace Energinet.DataHub.ProcessManager.Orchestrations.Shared;
namespace Energinet.DataHub.ProcessManagement.Core.Application.Api.Handlers;

public abstract class StartOrchestrationFromMessageHandlerBase<TInputParameterDto>(
public abstract class StartOrchestrationInstanceFromMessageHandlerBase<TInputParameterDto>(
ILogger logger)
where TInputParameterDto : IInputParameterDto
{
private readonly ILogger _logger = logger;

public Task StartOrchestration(ServiceBusReceivedMessage message)
public Task HandleAsync(ServiceBusReceivedMessage message)
{
using var serviceBusMessageLoggerScope = _logger.BeginScope(new
{
Expand Down Expand Up @@ -70,10 +70,10 @@ public Task StartOrchestration(ServiceBusReceivedMessage message)
message: $"Unable to parse {nameof(startOrchestrationDto.StartedByActorId)} to guid");
}

return StartOrchestration(
return StartOrchestrationInstanceAsync(
new ActorIdentity(new ActorId(actorId)),
inputParameterDto);
}

protected abstract Task StartOrchestration(ActorIdentity actorIdentity, TInputParameterDto input);
protected abstract Task StartOrchestrationInstanceAsync(ActorIdentity actorIdentity, TInputParameterDto input);
}
5 changes: 5 additions & 0 deletions source/ProcessManager.Core/ProcessManager.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.18.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
Expand All @@ -23,4 +24,8 @@
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.2.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ProcessManager.Abstractions\ProcessManager.Abstractions.csproj" />
</ItemGroup>

</Project>
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.Application.Api.Handlers;
using Energinet.DataHub.ProcessManagement.Core.Application.Orchestration;
using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance;
using Energinet.DataHub.ProcessManager.Api.Mappers;
Expand All @@ -22,11 +23,12 @@
namespace Energinet.DataHub.ProcessManager.Example.Orchestrations.Processes.BRS_X01.InputExample;

internal class SearchInputExampleHandler(
IOrchestrationInstanceQueries queries)
IOrchestrationInstanceQueries queries) :
ISearchOrchestrationInstancesQueryHandler<InputExampleQuery, InputExampleQueryResult>
{
private readonly IOrchestrationInstanceQueries _queries = queries;

public async Task<IReadOnlyCollection<InputExampleQueryResult>> SearchAsync(InputExampleQuery query)
public async Task<IReadOnlyCollection<InputExampleQueryResult>> HandleAsync(InputExampleQuery query)
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ public async Task<IActionResult> Run(
InputExampleQuery query,
FunctionContext executionContext)
{
var queryResultItems = await _handler.SearchAsync(query).ConfigureAwait(false);

var queryResultItems = await _handler.HandleAsync(query).ConfigureAwait(false);
return new OkObjectResult(queryResultItems);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async Task<IActionResult> Run(
ScheduleInputExampleCommandV1 command,
FunctionContext executionContext)
{
var orchestrationInstanceId = await _handler.ScheduleNewExampleAsync(command).ConfigureAwait(false);
return new OkObjectResult(orchestrationInstanceId.Value);
var orchestrationInstanceId = await _handler.HandleAsync(command).ConfigureAwait(false);
return new OkObjectResult(orchestrationInstanceId);
}
}
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.Application.Api.Handlers;
using Energinet.DataHub.ProcessManagement.Core.Application.Orchestration;
using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription;
using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance;
Expand All @@ -21,11 +22,13 @@
namespace Energinet.DataHub.ProcessManager.Example.Orchestrations.Processes.BRS_X01.InputExample.V1;

internal class StartInputExampleHandlerV1(
IStartOrchestrationInstanceCommands manager)
IStartOrchestrationInstanceCommands manager) :
IStartOrchestrationInstanceCommandHandler<StartInputExampleCommandV1, InputV1>,
IScheduleOrchestrationInstanceCommandHandler<ScheduleInputExampleCommandV1, InputV1>
{
private readonly IStartOrchestrationInstanceCommands _manager = manager;

public async Task<OrchestrationInstanceId> StartNewExampleAsync(StartInputExampleCommandV1 command)
public async Task<Guid> HandleAsync(StartInputExampleCommandV1 command)
{
// Here we show how its possible, based on input, to decide certain steps should be skipped by the orchestration.
IReadOnlyCollection<int> skipStepsBySequence = command.InputParameter.ShouldSkipSkippableStep
Expand All @@ -44,10 +47,10 @@ public async Task<OrchestrationInstanceId> StartNewExampleAsync(StartInputExampl
skipStepsBySequence: skipStepsBySequence)
.ConfigureAwait(false);

return orchestrationInstanceId;
return orchestrationInstanceId.Value;
}

public async Task<OrchestrationInstanceId> ScheduleNewExampleAsync(ScheduleInputExampleCommandV1 command)
public async Task<Guid> HandleAsync(ScheduleInputExampleCommandV1 command)
{
// Here we show how its possible, based on input, to decide certain steps should be skipped by the orchestration.
IReadOnlyCollection<int> skipStepsBySequence = command.InputParameter.ShouldSkipSkippableStep
Expand All @@ -67,6 +70,6 @@ public async Task<OrchestrationInstanceId> ScheduleNewExampleAsync(ScheduleInput
skipStepsBySequence: skipStepsBySequence)
.ConfigureAwait(false);

return orchestrationInstanceId;
return orchestrationInstanceId.Value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async Task<IActionResult> Run(
StartInputExampleCommandV1 command,
FunctionContext executionContext)
{
var orchestrationInstanceId = await _handler.StartNewExampleAsync(command).ConfigureAwait(false);
return new OkObjectResult(orchestrationInstanceId.Value);
var orchestrationInstanceId = await _handler.HandleAsync(command).ConfigureAwait(false);
return new OkObjectResult(orchestrationInstanceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Energinet.DataHub.ProcessManager.Client.Extensions.DependencyInjection;
using Energinet.DataHub.ProcessManager.Client.Extensions.Options;
using Energinet.DataHub.ProcessManager.Orchestrations.Abstractions.Processes.BRS_026.V1.Model;
using Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_026.V1;
using Energinet.DataHub.ProcessManager.Orchestrations.Tests.Fixtures;
using Energinet.DataHub.ProcessManager.Orchestrations.Tests.Fixtures.Extensions;
using FluentAssertions;
Expand Down Expand Up @@ -107,7 +108,7 @@ public async Task RequestCalculatedEnergyTimeSeries_WhenStarted_OrchestrationCom
// Assert
var orchestration = await _fixture.DurableClient.WaitForOrchestationStartedAsync(
createdTimeFrom: orchestrationCreatedAfter,
name: "Orchestration_RequestCalculatedEnergyTimeSeries_V1");
name: nameof(Orchestration_Brs_026_V1));
orchestration.Input.ToString().Should().Contain(businessReason);

var completedOrchestration = await _fixture.DurableClient.WaitForOrchestrationCompletedAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using Energinet.DataHub.ProcessManagement.Core.Application.Api.Handlers;
using Energinet.DataHub.ProcessManagement.Core.Application.Orchestration;
using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription;
using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance;
using Energinet.DataHub.ProcessManager.Orchestrations.Abstractions.Processes.BRS_021.ForwardMeteredData.V1.Model;
using Microsoft.Extensions.Logging;

namespace Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_021.ForwardMeteredData.V1;

public class StartForwardMeteredDataHandler(IStartOrchestrationInstanceCommands commands)
public class StartForwardMeteredDataHandlerV1(
ILogger<StartForwardMeteredDataHandlerV1> logger,
IStartOrchestrationInstanceCommands commands)
: StartOrchestrationInstanceFromMessageHandlerBase<MeteredDataForMeasurementPointMessageInputV1>(logger)
{
private readonly IStartOrchestrationInstanceCommands _commands = commands;

/// <summary>
/// Start forward metered data.
/// </summary>
public async Task StartForwardMeteredDataAsync(MeteredDataForMeasurementPointMessageInputV1 input)
protected override async Task StartOrchestrationInstanceAsync(ActorIdentity actorIdentity, MeteredDataForMeasurementPointMessageInputV1 input)
{
var orchestrationDescriptionUniqueName = new Brs_021_ForwardedMeteredData_V1();

await _commands.StartNewOrchestrationInstanceAsync(
identity: new ActorIdentity(new ActorId(input.AuthenticatedActorId)),
identity: actorIdentity,
uniqueName: new OrchestrationDescriptionUniqueName(
orchestrationDescriptionUniqueName.Name,
orchestrationDescriptionUniqueName.Version),
Expand Down

This file was deleted.

Loading

0 comments on commit d6cad01

Please sign in to comment.