fix(graph): migration 002 now tolerates legacy graph_nodes/edges schemas
Rewrites migration 002 to use ALTER TABLE ... IF EXISTS with per-column guards and a data-migration DO block that backfills document_json/written_at/batch_id from the older (tenant_id, data, created_at) layout when present. Updates GraphChangeStreamProcessor + SavedViewsMigrationHostedService for the aligned schema and extends the incremental processor tests for the new path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Graph.Indexer.Ingestion.Sbom;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
@@ -37,30 +38,30 @@ public sealed class GraphChangeStreamProcessor : BackgroundService
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
protected override Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
=> RunPollingLoopAsync(stoppingToken);
|
||||
|
||||
internal async Task RunPollingLoopAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
using var pollTimer = new PeriodicTimer(_options.PollInterval);
|
||||
using var backfillTimer = new PeriodicTimer(_options.BackfillInterval);
|
||||
var backfillStopwatch = Stopwatch.StartNew();
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
try
|
||||
{
|
||||
var pollTask = pollTimer.WaitForNextTickAsync(stoppingToken).AsTask();
|
||||
var backfillTask = backfillTimer.WaitForNextTickAsync(stoppingToken).AsTask();
|
||||
|
||||
var completed = await Task.WhenAny(pollTask, backfillTask).ConfigureAwait(false);
|
||||
if (completed.IsCanceled || stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (completed == pollTask)
|
||||
while (await pollTimer.WaitForNextTickAsync(stoppingToken).ConfigureAwait(false))
|
||||
{
|
||||
await ApplyStreamAsync(isBackfill: false, stoppingToken).ConfigureAwait(false);
|
||||
|
||||
if (_options.BackfillInterval <= TimeSpan.Zero || backfillStopwatch.Elapsed >= _options.BackfillInterval)
|
||||
{
|
||||
await ApplyStreamAsync(isBackfill: true, stoppingToken).ConfigureAwait(false);
|
||||
backfillStopwatch.Restart();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ApplyStreamAsync(isBackfill: true, stoppingToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
// Graceful BackgroundService shutdown.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user