feat(FinishEnvelopeJob): add PDF burning with concurrency control
- Introduced PDFBurnerParams configuration for concurrency limit. - Added SemaphoreSlim to handle concurrent PDF burning for envelopes. - Updated job to call _mediator.BurnPdf for each envelope with error handling. - Preserved logging of job execution and envelope UUIDs.
This commit is contained in:
@@ -9,6 +9,11 @@ namespace EnvelopeGenerator.Application.Common.Configurations;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PDFBurnerParams : ITextStyle
|
public class PDFBurnerParams : ITextStyle
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public int ConcurrencyLimit { get; set; } = 5;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public static class BurnPdfCommandExtensions
|
|||||||
/// <param name="envelopeId"></param>
|
/// <param name="envelopeId"></param>
|
||||||
/// <param name="cancel"></param>
|
/// <param name="cancel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Task<byte[]> BurnPdf(this ISender sender, int envelopeId, CancellationToken cancel)
|
public static Task<byte[]> BurnPdf(this ISender sender, int envelopeId, CancellationToken cancel = default)
|
||||||
=> sender.Send(new BurnPdfCommand(EnvelopeId: envelopeId), cancel);
|
=> sender.Send(new BurnPdfCommand(EnvelopeId: envelopeId), cancel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -42,7 +42,7 @@ public static class BurnPdfCommandExtensions
|
|||||||
/// <param name="envelopeUuid"></param>
|
/// <param name="envelopeUuid"></param>
|
||||||
/// <param name="cancel"></param>
|
/// <param name="cancel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Task<byte[]> BurnPdf(this ISender sender, string envelopeUuid, CancellationToken cancel)
|
public static Task<byte[]> BurnPdf(this ISender sender, string envelopeUuid, CancellationToken cancel = default)
|
||||||
=> sender.Send(new BurnPdfCommand(EnvelopeUuid: envelopeUuid), cancel);
|
=> sender.Send(new BurnPdfCommand(EnvelopeUuid: envelopeUuid), cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
using EnvelopeGenerator.Application.Common.Configurations;
|
||||||
using EnvelopeGenerator.Application.Envelopes.Queries;
|
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||||
|
using EnvelopeGenerator.Application.Pdf;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
using EnvelopeGenerator.Finalizer.Models;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
@@ -13,10 +14,13 @@ namespace EnvelopeGenerator.Finalizer.Job
|
|||||||
|
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
public FinishEnvelopeJob(ILogger<FinishEnvelopeJob> logger, IMediator mediator)
|
private readonly PDFBurnerParams _options;
|
||||||
|
|
||||||
|
public FinishEnvelopeJob(ILogger<FinishEnvelopeJob> logger, IMediator mediator, IOptions<PDFBurnerParams> options)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
|
_options = options.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Execute(IJobExecutionContext context)
|
public async Task Execute(IJobExecutionContext context)
|
||||||
@@ -29,23 +33,39 @@ namespace EnvelopeGenerator.Finalizer.Job
|
|||||||
HasDocResult = false
|
HasDocResult = false
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|
||||||
foreach (var envelope in envelopes)
|
using var semaphore = new SemaphoreSlim(_options.ConcurrencyLimit);
|
||||||
|
await Task.WhenAll(envelopes.Select(async envelope =>
|
||||||
{
|
{
|
||||||
// add sub-steps
|
await semaphore.WaitAsync(cancel);
|
||||||
}
|
try
|
||||||
|
{
|
||||||
|
await _mediator.BurnPdf(envelope.Id, cancel);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error burning envelope {EnvelopeId}", envelope.Id);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
semaphore.Release();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
if (envelopes.Any())
|
var envelopeCount = envelopes.Count();
|
||||||
|
if (envelopeCount > 0)
|
||||||
|
{
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Job '{JobName}' executed at {Timestamp}. {EnvelopeCount} envelope(s) successfully finalized. UUID(s): {EnvelopeUuids}",
|
"Job '{JobName}' executed at {Timestamp}. {EnvelopeCount} envelope(s) successfully finalized. UUID(s): {EnvelopeUuids}",
|
||||||
context.JobDetail.Key.Name,
|
context.JobDetail.Key.Name,
|
||||||
DateTimeOffset.Now,
|
context.FireTimeUtc.ToLocalTime(),
|
||||||
envelopes.Count(),
|
envelopeCount,
|
||||||
string.Join(", ", envelopes.Select(e => e.Uuid))
|
string.Join(", ", envelopes.Select(e => e.Uuid))
|
||||||
);
|
);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_logger.LogInformation("Job '{JobName}' executed successfully at {Timestamp}. No envelopes were finalized.",
|
_logger.LogInformation("Job '{JobName}' executed successfully at {Timestamp}. No envelopes were finalized.",
|
||||||
context.JobDetail.Key.Name,
|
context.JobDetail.Key.Name,
|
||||||
DateTimeOffset.Now
|
context.FireTimeUtc.ToLocalTime()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user