fix(transport): drop the external-definition lookup cache after a committed bundle import (ScadaBridge#83)
The bundle importer writes external systems, methods and database connections through the raw DbContext, bypassing the ManagementActor handlers that invalidate ExternalDefinitionLookupCache (#65), so the importing node served pre-import definitions for up to DefinitionCacheTtl. New Commons seam IExternalDefinitionCacheInvalidator, implemented by the cache and registered as the same singleton; BundleImporter takes it optionally and invalidates once after every committed import (never on rollback; never throws). Peer-central-node invalidation (the other half of #83) is NOT done here: the issue leaves open whether the 10 s TTL bound is acceptable for the peer. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -95,6 +95,9 @@ public sealed class BundleImporter : IBundleImporter
|
||||
// derives watermark bumps from the change tracker. Null in hosts that don't
|
||||
// register it; the caches then simply never get this invalidation signal.
|
||||
private readonly ITemplateGraphWatermark? _watermark;
|
||||
// Optional (Gitea #83): drops this node's external-definition lookup cache after a
|
||||
// committed import. Null on hosts without the External System Gateway.
|
||||
private readonly IExternalDefinitionCacheInvalidator? _definitionCacheInvalidator;
|
||||
private readonly ILogger<BundleImporter>? _logger;
|
||||
|
||||
/// <summary>
|
||||
@@ -121,6 +124,7 @@ public sealed class BundleImporter : IBundleImporter
|
||||
/// <param name="scriptArtifactChangeBus">Optional: node-local bus notified AFTER a successful commit that script-bearing artifacts (ApiMethod / SharedScript / Template) were overwritten or renamed, so compiled-handler caches can invalidate. Null on hosts that don't register it (staleness/invalidation then relies on the consumer's own self-heal).</param>
|
||||
/// <param name="logger">Optional logger.</param>
|
||||
/// <param name="watermark">Optional: template-graph version watermark, bumped once per apply attempt so the flatten-session caches and the process-wide staleness memo cannot serve pre-import (or rolled-back) readings. Null on hosts that don't register it.</param>
|
||||
/// <param name="definitionCacheInvalidator">Optional (Gitea #83): drops this node's external-system / database-connection definition cache after a committed import, so imported definitions take effect immediately rather than after the cache TTL. Null on hosts without the External System Gateway.</param>
|
||||
public BundleImporter(
|
||||
BundleSerializer bundleSerializer,
|
||||
ManifestValidator manifestValidator,
|
||||
@@ -142,7 +146,8 @@ public sealed class BundleImporter : IBundleImporter
|
||||
IStaleInstanceProbe? staleInstanceProbe = null,
|
||||
IScriptArtifactChangeBus? scriptArtifactChangeBus = null,
|
||||
ILogger<BundleImporter>? logger = null,
|
||||
ITemplateGraphWatermark? watermark = null)
|
||||
ITemplateGraphWatermark? watermark = null,
|
||||
IExternalDefinitionCacheInvalidator? definitionCacheInvalidator = null)
|
||||
{
|
||||
_bundleSerializer = bundleSerializer ?? throw new ArgumentNullException(nameof(bundleSerializer));
|
||||
_manifestValidator = manifestValidator ?? throw new ArgumentNullException(nameof(manifestValidator));
|
||||
@@ -164,6 +169,7 @@ public sealed class BundleImporter : IBundleImporter
|
||||
_staleInstanceProbe = staleInstanceProbe;
|
||||
_scriptArtifactChangeBus = scriptArtifactChangeBus;
|
||||
_watermark = watermark;
|
||||
_definitionCacheInvalidator = definitionCacheInvalidator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -1697,6 +1703,7 @@ public sealed class BundleImporter : IBundleImporter
|
||||
// Post-commit side effects — run ONCE, only after a durable commit, so a
|
||||
// retried attempt neither publishes twice nor releases the session early.
|
||||
PublishScriptArtifactChanges(resolutions);
|
||||
InvalidateExternalDefinitionCache();
|
||||
|
||||
// T-007: zero out the decrypted plaintext BEFORE remove so any
|
||||
// caller-held reference (e.g. the Razor page that built the
|
||||
@@ -2442,6 +2449,32 @@ public sealed class BundleImporter : IBundleImporter
|
||||
/// (nothing was written). Fully guarded: never throws (it runs after the transaction
|
||||
/// has committed).
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Gitea #83: the importer writes external systems, their methods and database connections
|
||||
/// through the raw <c>ScadaBridgeDbContext</c>, bypassing the ManagementActor handlers that
|
||||
/// drop <c>ExternalDefinitionLookupCache</c> (Gitea #65), so without this the importing node
|
||||
/// served the pre-import definition for up to <c>DefinitionCacheTtl</c>. Invalidates on every
|
||||
/// committed import rather than only when an external entity was resolved: dependencies can
|
||||
/// pull definitions in implicitly, imports are rare, and a cleared cache only costs one
|
||||
/// re-query per name. Never throws (the transaction has already committed).
|
||||
/// </summary>
|
||||
private void InvalidateExternalDefinitionCache()
|
||||
{
|
||||
if (_definitionCacheInvalidator is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_definitionCacheInvalidator.InvalidateAll();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogError(ex, "Invalidating the external-definition cache after a committed bundle import failed; ignored (the cache TTL still bounds staleness).");
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishScriptArtifactChanges(IReadOnlyList<ImportResolution> resolutions)
|
||||
{
|
||||
if (_scriptArtifactChangeBus is null)
|
||||
|
||||
Reference in New Issue
Block a user