< Summary

Information
Class: Elsa.Platform.Integration.Services.ElsaPlatformDeploymentWorker
Assembly: Elsa.Platform.Integration
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Platform.Integration/Services/ElsaPlatformDeploymentWorker.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 99
Coverable lines: 99
Total lines: 157
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 36
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
ExecuteAsync()0%2040%
ProcessAvailableCommandsAsync()0%4260%
ProcessClaimedCommandAsync()0%702260%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Platform.Integration/Services/ElsaPlatformDeploymentWorker.cs

#LineLine coverage
 1using Elsa.Platform.Integration.Models;
 2using Elsa.Platform.Integration.Options;
 3using Microsoft.Extensions.DependencyInjection;
 4using Microsoft.Extensions.Hosting;
 5using Microsoft.Extensions.Logging;
 6using Microsoft.Extensions.Options;
 7
 8namespace Elsa.Platform.Integration.Services;
 9
 010public class ElsaPlatformDeploymentWorker(
 011    IServiceScopeFactory scopeFactory,
 012    IOptions<ElsaPlatformIntegrationOptions> options,
 013    ILogger<ElsaPlatformDeploymentWorker> logger) : BackgroundService
 14{
 015    private readonly ElsaPlatformIntegrationOptions _options = options.Value;
 16
 17    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 18    {
 019        _options.Validate();
 020        if (!_options.Enabled)
 021            return;
 22
 023        while (!stoppingToken.IsCancellationRequested)
 24        {
 25            try
 26            {
 027                await ProcessAvailableCommandsAsync(stoppingToken);
 028            }
 029            catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
 30            {
 031                return;
 32            }
 033            catch (Exception ex)
 34            {
 035                logger.LogError(ex, "Elsa Platform deployment worker failed while polling commands.");
 036            }
 37
 038            await Task.Delay(_options.PollInterval, stoppingToken);
 39        }
 040    }
 41
 42    private async Task ProcessAvailableCommandsAsync(CancellationToken cancellationToken)
 43    {
 044        await using var scope = scopeFactory.CreateAsyncScope();
 045        var client = scope.ServiceProvider.GetRequiredService<IPlatformRuntimeCommandClient>();
 046        var applier = scope.ServiceProvider.GetRequiredService<IPlatformRecipeArtifactApplier>();
 047        var commands = await client.PollAsync(cancellationToken);
 48
 049        foreach (var command in commands)
 50        {
 051            var claim = await client.ClaimAsync(command.Id, cancellationToken);
 052            if (claim is null)
 53                continue;
 54
 055            await ProcessClaimedCommandAsync(client, applier, claim, cancellationToken);
 56        }
 057    }
 58
 59    private async Task ProcessClaimedCommandAsync(
 60        IPlatformRuntimeCommandClient client,
 61        IPlatformRecipeArtifactApplier applier,
 62        PlatformRuntimeCommandClaimResponse claim,
 63        CancellationToken cancellationToken)
 64    {
 065        var command = claim.Command;
 066        if (command.Action is not PlatformRuntimeCommandAction.Deploy and not PlatformRuntimeCommandAction.Rollback)
 67        {
 068            await client.RejectAsync(
 069                command.Id,
 070                new PlatformRuntimeCommandRejectRequest(
 071                    claim.LeaseToken,
 072                    [PlatformDiagnosticSanitizer.Error("elsa-platform.command-unsupported", "Runtime command action is n
 073                cancellationToken);
 074            return;
 75        }
 76
 077        if (command.Artifacts is not { Count: > 0 })
 78        {
 079            await client.RejectAsync(
 080                command.Id,
 081                new PlatformRuntimeCommandRejectRequest(
 082                    claim.LeaseToken,
 083                    [PlatformDiagnosticSanitizer.Error("elsa-platform.artifact-missing", "Runtime command did not includ
 084                cancellationToken);
 085            return;
 86        }
 87
 088        var outcomes = new List<PlatformArtifactOutcome>();
 89        try
 90        {
 091            foreach (var artifact in command.Artifacts)
 92            {
 093                await client.ReportProgressAsync(command.Id, claim.LeaseToken, "downloading", 20, "Downloading recipe ar
 094                await using var artifactZip = await client.DownloadArtifactAsync(command, artifact, claim.LeaseToken, ca
 095                await client.ReportProgressAsync(command.Id, claim.LeaseToken, "applying", 60, "Applying recipe artifact
 096                var result = await applier.ApplyAsync(command, artifact, artifactZip, cancellationToken);
 097                outcomes.Add(new PlatformArtifactOutcome(
 098                    artifact.ArtifactRecordId,
 099                    result.Status,
 0100                    result.ObservedDigest,
 0101                    result.RuntimeReference,
 0102                    result.Diagnostics));
 103
 0104                if (!result.Succeeded)
 105                    break;
 0106            }
 107
 0108            var failed = outcomes.FirstOrDefault(x => x.Status == PlatformArtifactStatus.Failed);
 0109            if (failed is not null)
 110            {
 0111                await client.FailAsync(
 0112                    command.Id,
 0113                    new PlatformRuntimeCommandFailRequest(
 0114                        claim.LeaseToken,
 0115                        failed.Diagnostics ?? [PlatformDiagnosticSanitizer.Error("elsa-platform.artifact-failed", "Recip
 0116                        outcomes),
 0117                    cancellationToken);
 0118                return;
 119            }
 120
 0121            var rejected = outcomes.FirstOrDefault(x => x.Status == PlatformArtifactStatus.Rejected);
 0122            if (rejected is not null)
 123            {
 0124                await client.RejectAsync(
 0125                    command.Id,
 0126                    new PlatformRuntimeCommandRejectRequest(
 0127                        claim.LeaseToken,
 0128                        rejected.Diagnostics ?? [PlatformDiagnosticSanitizer.Error("elsa-platform.artifact-rejected", "R
 0129                        outcomes),
 0130                    cancellationToken);
 0131                return;
 132            }
 133
 0134            var first = outcomes.FirstOrDefault();
 0135            await client.CompleteAsync(
 0136                command.Id,
 0137                new PlatformRuntimeCommandCompleteRequest(
 0138                    claim.LeaseToken,
 0139                    first?.ObservedDigest,
 0140                    first?.RuntimeReference,
 0141                    [PlatformDiagnosticSanitizer.Info("elsa-platform.command-completed", "Recipe deployment command comp
 0142                    outcomes),
 0143                cancellationToken);
 0144        }
 0145        catch (Exception ex) when (ex is not OperationCanceledException)
 146        {
 0147            logger.LogError(ex, "Elsa Platform deployment worker failed to apply command {CommandId}.", command.Id);
 0148            await client.FailAsync(
 0149                command.Id,
 0150                new PlatformRuntimeCommandFailRequest(
 0151                    claim.LeaseToken,
 0152                    [PlatformDiagnosticSanitizer.Error("elsa-platform.command-failed", ex.Message)],
 0153                    outcomes),
 0154                cancellationToken);
 155        }
 0156    }
 157}