Handle cancelled history reads gracefully
Handles cancellation separately in analytics and scan history reads, and centralizes scan history DTO mapping to reduce duplicated code.main
parent
c60bfec891
commit
bd4fd0d4b5
|
|
@ -27,6 +27,7 @@ builder.Services
|
|||
.AddOptions<DesktopHostOptions>()
|
||||
.Bind(builder.Configuration.GetSection(DesktopHostOptions.SectionName));
|
||||
|
||||
builder.Services.AddSingleton<DesktopShutdownService>();
|
||||
builder.Services.AddHostedService<LaunchBrowserHostedService>();
|
||||
|
||||
builder.Services.AddControllersWithViews();
|
||||
|
|
@ -76,7 +77,10 @@ if (!app.Environment.IsDevelopment())
|
|||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
if (KestrelConfiguration.HasHttpsEndpoint(app.Configuration))
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
}
|
||||
app.UseRouting();
|
||||
app.UseAuthorization();
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>false</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>\\FileServer\Edata\Deployments-by-DotNet-Team\Deployment-By-Mustafa\AVSSHIPPINGMARK</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<ProjectGuid>fcd78a4e-cf57-4247-9698-bb63ba85b062</ProjectGuid>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -53,6 +53,11 @@ public sealed class MovementAnalyticsService(
|
|||
.Where(x => x.ProcessedAtUtc >= rangeStartUtc && x.ProcessedAtUtc <= rangeEndUtc)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException exception) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogDebug(exception, "Movement analytics read was cancelled.");
|
||||
throw;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Failed to load movement analytics.");
|
||||
|
|
|
|||
|
|
@ -70,16 +70,11 @@ public sealed class SqliteScanHistoryStore(
|
|||
.Take(5)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return entries
|
||||
.Select(x => new ScannedRecordDto
|
||||
return MapSuccessful(entries);
|
||||
}
|
||||
catch (Exception exception) when (TryHandleReadCancellation(exception, cancellationToken, "Successful scan history (last five)"))
|
||||
{
|
||||
ModelNumber = x.ModelNumber,
|
||||
UniqueNumber = x.UniqueNumber,
|
||||
ExistsInSystem = x.ExistsInSystem,
|
||||
ShipmentMarked = x.ShipmentMarked,
|
||||
ProcessedAtUtc = DateTime.SpecifyKind(x.ProcessedAtUtc, DateTimeKind.Utc)
|
||||
})
|
||||
.ToArray();
|
||||
return Array.Empty<ScannedRecordDto>();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
|
@ -98,16 +93,11 @@ public sealed class SqliteScanHistoryStore(
|
|||
.Take(5)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return entries
|
||||
.Select(x => new RejectedScanRecordDto
|
||||
return MapRejected(entries);
|
||||
}
|
||||
catch (Exception exception) when (TryHandleReadCancellation(exception, cancellationToken, "Rejected scan history (last five)"))
|
||||
{
|
||||
RawInputValue = x.RawInputValue,
|
||||
ModelNumber = x.ModelNumber,
|
||||
UniqueNumber = x.UniqueNumber,
|
||||
RejectionReason = x.RejectionReason,
|
||||
ProcessedAtUtc = DateTime.SpecifyKind(x.ProcessedAtUtc, DateTimeKind.Utc)
|
||||
})
|
||||
.ToArray();
|
||||
return Array.Empty<RejectedScanRecordDto>();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
|
@ -126,16 +116,11 @@ public sealed class SqliteScanHistoryStore(
|
|||
.OrderByDescending(x => x.ProcessedAtUtc)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return entries
|
||||
.Select(x => new ScannedRecordDto
|
||||
return MapSuccessful(entries);
|
||||
}
|
||||
catch (Exception exception) when (TryHandleReadCancellation(exception, cancellationToken, "Successful scan history (all)"))
|
||||
{
|
||||
ModelNumber = x.ModelNumber,
|
||||
UniqueNumber = x.UniqueNumber,
|
||||
ExistsInSystem = x.ExistsInSystem,
|
||||
ShipmentMarked = x.ShipmentMarked,
|
||||
ProcessedAtUtc = DateTime.SpecifyKind(x.ProcessedAtUtc, DateTimeKind.Utc)
|
||||
})
|
||||
.ToArray();
|
||||
return Array.Empty<ScannedRecordDto>();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
|
@ -153,7 +138,44 @@ public sealed class SqliteScanHistoryStore(
|
|||
.OrderByDescending(x => x.ProcessedAtUtc)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return entries
|
||||
return MapRejected(entries);
|
||||
}
|
||||
catch (Exception exception) when (TryHandleReadCancellation(exception, cancellationToken, "Rejected scan history (all)"))
|
||||
{
|
||||
return Array.Empty<RejectedScanRecordDto>();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Failed to read full rejected scan history.");
|
||||
return Array.Empty<RejectedScanRecordDto>();
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryHandleReadCancellation(Exception exception, CancellationToken cancellationToken, string operation)
|
||||
{
|
||||
if (exception is not OperationCanceledException || !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.LogDebug(exception, "{Operation} read was cancelled.", operation);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ScannedRecordDto[] MapSuccessful(IEnumerable<ScanHistoryEntry> entries) =>
|
||||
entries
|
||||
.Select(x => new ScannedRecordDto
|
||||
{
|
||||
ModelNumber = x.ModelNumber,
|
||||
UniqueNumber = x.UniqueNumber,
|
||||
ExistsInSystem = x.ExistsInSystem,
|
||||
ShipmentMarked = x.ShipmentMarked,
|
||||
ProcessedAtUtc = DateTime.SpecifyKind(x.ProcessedAtUtc, DateTimeKind.Utc)
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
private static RejectedScanRecordDto[] MapRejected(IEnumerable<RejectedScanEntry> entries) =>
|
||||
entries
|
||||
.Select(x => new RejectedScanRecordDto
|
||||
{
|
||||
RawInputValue = x.RawInputValue,
|
||||
|
|
@ -163,13 +185,6 @@ public sealed class SqliteScanHistoryStore(
|
|||
ProcessedAtUtc = DateTime.SpecifyKind(x.ProcessedAtUtc, DateTimeKind.Utc)
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Failed to read full rejected scan history.");
|
||||
return Array.Empty<RejectedScanRecordDto>();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TrimSuccessfulAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "10.0.8",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue