Skip to content

SingletonGuard

Namespace AgentPrism · Assembly AgentPrism.Core.dll

Reduces a background service’s execution to a single instance cluster-wide.

public sealed class SingletonGuard

objectSingletonGuard

object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

SingletonGuard.RunAsync runs its own lease/renew loop at an interval that is ONE THIRD of SingletonExecutionOptions.LeaseDuration; this keeps the lease alive in cases where the calling service’s own work interval (e.g. MCP discovery’s 5-minute refresh interval) may be much longer than the lease duration. The calling service reads only SingletonGuard.IsHeld on each of its own ticks - this is synchronous and free, it produces no extra database round-trip.

While SingletonExecutionOptions.Enabled is false (the default), SingletonGuard.RunAsync returns immediately without issuing ANY query to the store, and SingletonGuard.IsHeld always stays true - today’s single-instance behavior is preserved exactly.

This type is not internal, it is public: it needs to be usable from a separate assembly such as AgentPrism.Mcp, and InternalsVisibleTo covers only its own test projects, not sibling packages. This is why the plan’s suggestion of an “internal helper” could not be implemented.

SingletonGuard(ISingletonLeaseStore, IOptionsMonitor<SingletonExecutionOptions>, string, ILogger?)

Section titled “ SingletonGuard(ISingletonLeaseStore, IOptionsMonitor<SingletonExecutionOptions>, string, ILogger?)”

Creates a new single-executor guard.

public SingletonGuard(ISingletonLeaseStore store, IOptionsMonitor<SingletonExecutionOptions> optionsMonitor, string leaseName, ILogger? logger = null)

store ISingletonLeaseStore

Lease store.

optionsMonitor IOptionsMonitor<SingletonExecutionOptions>

Single-executor selection settings.

leaseName string

Cluster-wide unique name of the protected work.

logger ILogger?

Logger to which lease-loss and error logs are written.

ArgumentNullException

store or optionsMonitor is null.

ArgumentException

leaseName is empty.

Whether this instance currently holds the lease. Always true when single-executor selection is disabled. Synchronous; the calling service can read this on every tick for free.

public bool IsHeld { get; }

bool

Starts the lease/renew loop. Returns immediately without issuing ANY query to the store when single-executor selection is disabled. When stoppingToken is cancelled, the lease (if held) is released and the task completes.

public Task RunAsync(CancellationToken stoppingToken)

stoppingToken CancellationToken

The host service’s stop token.

Task

The task representing the loop.