Table of Contents

Class LoginServerSigningKeyService

Namespace
FishMMO.Database.Npgsql.Services
Assembly
FishMMO-DB.dll

Service for managing per-LoginServer HMAC signing keys. Uses EF Core compiled queries for the hot validation path and raw SQL for inserts.

public sealed class LoginServerSigningKeyService : BaseService<LoginServerSigningKeyEntity>, ILoginServerSigningKeyService
Inheritance
LoginServerSigningKeyService
Implements
Inherited Members

Constructors

LoginServerSigningKeyService(INpgsqlDbContextFactory)

public LoginServerSigningKeyService(INpgsqlDbContextFactory dbContextFactory)

Parameters

dbContextFactory INpgsqlDbContextFactory

LoginServerSigningKeyService(INpgsqlDbContextFactory, int)

public LoginServerSigningKeyService(INpgsqlDbContextFactory dbContextFactory, int keyOverlapWindowDays)

Parameters

dbContextFactory INpgsqlDbContextFactory
keyOverlapWindowDays int

Properties

KeyOverlapWindowDays

Verification overlap window (in days) during which rotated-out keys are still kept in the table so in-flight tokens signed before rotation can be validated. The value is injected at construction time and defaults to 7 days.

public int KeyOverlapWindowDays { get; }

Property Value

int

Methods

DeleteAsync(long, CancellationToken)

Deletes the signing key for a specific LoginServer. Called during LoginServer shutdown or key rotation.

public Task<DatabaseResult> DeleteAsync(long loginServerId, CancellationToken cancellationToken = default)

Parameters

loginServerId long
cancellationToken CancellationToken

Returns

Task<DatabaseResult>

FetchByIdAsync(long, CancellationToken)

Fetches a signing key by its token-embedded database ID.

public Task<DatabaseResult<LoginServerSigningKeyData>> FetchByIdAsync(long signingKeyId, CancellationToken cancellationToken = default)

Parameters

signingKeyId long
cancellationToken CancellationToken

Returns

Task<DatabaseResult<LoginServerSigningKeyData>>

FetchByLoginServerIdAsync(long, CancellationToken)

Fetches the signing key for a specific LoginServer. Called by WorldServers and SceneServers during token validation.

public Task<DatabaseResult<LoginServerSigningKeyData>> FetchByLoginServerIdAsync(long loginServerId, CancellationToken cancellationToken = default)

Parameters

loginServerId long
cancellationToken CancellationToken

Returns

Task<DatabaseResult<LoginServerSigningKeyData>>

UpsertAsync(long, byte[], CancellationToken)

Upserts the active signing key for the specified LoginServer.

DUAL-LAYER EXECUTION CONTROL:

Outer layer — ExecuteWriteAsync retry loop (defined in BaseService): Wraps the entire operation in a configurable retry policy (up to 3 attempts with exponential backoff). If the inner execution strategy or transaction fails transiently (e.g. serialisation error, deadlock victim), the outer loop retries from scratch — creating a fresh DbContext and re-entering the execution strategy.

Inner layer — execution strategy with explicit transaction: The DbContext.Database.CreateExecutionStrategy() provides Npgsql's built-in retry-on-serialisation-failure inside the transaction scope. The explicit transaction itself ensures atomicity of the deactivate-INSERT pair: if the INSERT fails, the UPDATE is rolled back and no key is lost. The partial UNIQUE index on (login_server_id) WHERE is_active=true additionally serialises concurrent rotations.

This dual-layer design was chosen because the outer retry handles connection-level failures (pool exhaustion, DNS flake, TCP reset) while the inner strategy handles database-level contention (serialisation failures, unique-index violations). Each layer retries at its own granularity without conflating the two failure modes.

public Task<DatabaseResult<LoginServerSigningKeyData>> UpsertAsync(long loginServerId, byte[] hmacKey, CancellationToken cancellationToken = default)

Parameters

loginServerId long
hmacKey byte[]
cancellationToken CancellationToken

Returns

Task<DatabaseResult<LoginServerSigningKeyData>>