Skip to content

Conversation

@Aaronontheweb
Copy link
Member

@Aaronontheweb Aaronontheweb commented Oct 21, 2025

Summary

Implements proactive connectivity health checks for Akka.Persistence.Sql across all supported database providers (SQLite, PostgreSQL, MySQL, SQL Server). These checks complement existing CircuitBreaker-based readiness checks by providing continuous liveness verification.

  • SqlJournalConnectivityCheck: Lightweight database connectivity probe for journals
  • SqlSnapshotStoreConnectivityCheck: Lightweight database connectivity probe for snapshot stores
  • Builder extension methods: .WithConnectivityCheck() for fluent builder configuration
  • Comprehensive test coverage: 22 tests across all 4 database types

Implementation Details

Design

  • Uses Linq2Db DataConnection with lightweight SELECT 1 probes
  • Handles timeout, connection, and general exceptions appropriately
  • Returns HealthStatus.Healthy when connected, Unhealthy when disconnected
  • Supports custom HealthStatus configuration via builder

Classes

  • SqlJournalConnectivityCheck - Public, sealed
  • SqlSnapshotStoreConnectivityCheck - Public, sealed
  • SqlConnectivityCheckExtensions - Builder extension methods with reflection-based property access

Testing

✅ SQLite: 10 tests (healthy, unhealthy, parameter validation)
✅ PostgreSQL: 4 tests (healthy/unhealthy for journal & snapshot)
✅ MySQL: 4 tests (healthy/unhealthy for journal & snapshot)
✅ SQL Server: 4 tests (healthy/unhealthy for journal & snapshot)

All tests verify:

  • Healthy status when connected to valid database
  • Unhealthy status when connection fails
  • Proper error information in health check results

Related Issues

  • Closes Akka.Hosting Epic: akkadotnet/Akka.Hosting#678 - Add Connectivity Health Checks for Akka.Persistence Plugins
  • Relates to Discord discussion: Current health checks only use CircuitBreaker (reactive), need proactive connectivity verification

Test Plan

Run all connectivity check tests:

dotnet test src/Akka.Persistence.Sql.Hosting.Tests/Akka.Persistence.Sql.Hosting.Tests.csproj -c Release --filter "ConnectivityCheckSpec"

Expected: All 22 tests pass (requires Docker for PostgreSQL, MySQL, SQL Server)

- Add SqlJournalConnectivityCheck class for proactive database connectivity verification
- Add SqlSnapshotStoreConnectivityCheck class for snapshot store connectivity verification
- Add WithConnectivityCheck() extension methods for journal and snapshot store builders
- Implement lightweight SELECT 1 probes using Linq2Db DataConnection
- Comprehensive test coverage for connectivity checks in both healthy and unhealthy states
- Parameter validation tests for all required configuration
- Tests verify checks return Healthy when database connected, Unhealthy when disconnected

Closes #678 (partial - SQL implementation)
- Remove unnecessary parameterization complexity
- Use SqliteContainer directly as test fixture
- Keep tests focused and clean with straightforward Fact tests
- All 10 tests pass: 4 happy path, 4 unhappy path, 2 parameter validation
- Follows Akka.NET pattern of simple concrete test classes per provider
- Future: Add separate test classes for PostgreSQL, SQL Server, MySQL if needed
- PostgreSQL connectivity checks (4 tests)
- MySQL connectivity checks (4 tests)
- SQL Server connectivity checks (4 tests)
- Tests verify healthy status on valid connection, unhealthy on invalid connection
- All tests support both journal and snapshot store connectivity probes
- Total: 22 tests passing across all 4 SQL database types (SQLite, PostgreSQL, MySQL, SQL Server)

Closes #678 (SQL implementation complete)
@Aaronontheweb Aaronontheweb force-pushed the feature/sql-connectivity-health-checks branch from ab0eab2 to 03e69cc Compare October 21, 2025 19:43
Windows CI environment doesn't support Docker, causing test failures when attempting to initialize
SqlServerContainer, PostgreSqlContainer, and MySqlContainer. Added [SkipWindows] attribute to these
test classes to skip them on Windows while allowing Linux CI to run the full test suite.

- Added [SkipWindows] attribute to SqlServerConnectivityCheckSpec
- Added [SkipWindows] attribute to PostgreSqlConnectivityCheckSpec
- Added [SkipWindows] attribute to MySqlConnectivityCheckSpec
- Added required using statement for Akka.Persistence.Sql.Tests.Common.Internal.Xunit
The SqlFrameworkDiscoverer.IsValidTestClass() method had inverted logic that prevented
[SkipWindows] and [SkipLinux] attributes from working correctly. The method was returning
true when tests should be skipped instead of false.

Changed the return statement from:
  return !type.IsAbstract || type.IsSealed || skipLinux || skipWindows;
To:
  return (!type.IsAbstract || type.IsSealed) && !skipLinux && !skipWindows;

This ensures Docker-based connectivity check tests are properly skipped on Windows CI where
Docker is not available, fixing test failures in PostgreSqlConnectivityCheckSpec,
SqlServerConnectivityCheckSpec, and MySqlConnectivityCheckSpec.
The Akka.Persistence.Sql.Hosting.Tests project was missing the TestFramework attribute
registration that enables the custom SqlTestFramework, which provides platform-specific
test skipping via [SkipWindows] and [SkipLinux] attributes.

Created Properties/AssemblyInfo.cs with the TestFramework attribute to register the
SqlTestFramework. This enables the Docker-based connectivity check tests to be properly
skipped on Windows CI where Docker is unavailable.
Replace Environment.OSVersion.Platform with RuntimeInformation.IsOSPlatform
for more reliable platform detection across all .NET versions. This ensures
the test skipping mechanism works correctly on all platforms, particularly
for Windows CI environments where Docker containers are not available.
The changes to SqlFrameworkDiscoverer were causing test execution issues.
The AssemblyInfo.cs registration alone is sufficient to enable the
[SkipWindows] attribute functionality for the connectivity check tests.
- Upgraded Akka.Hosting from 1.5.53 to 1.5.55-beta1
- Upgraded Akka.NET from 1.5.53 to 1.5.55
- Updated SqlConnectivityCheckExtensions to use the new WithCustomHealthCheck() method
- Removed reflection-based approach in favor of the new public API
- All 22 connectivity health check tests pass successfully
Copy link
Member Author

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original review

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed this to ensure that we use the SqlFrameworkDiscoverer and skip Docker-based integration tests on Windows CI/CD

/// </summary>
public static class SqlConnectivityCheckExtensions
{
private static readonly System.Reflection.PropertyInfo? JournalBuilderProperty =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to get rid of that - should be able to just access the journal builder directly

new[] { "akka", "persistence", "sql", "snapshot-store", "connectivity" });

// Use reflection to access the internal Builder property
if (SnapshotBuilderProperty?.GetValue(builder) is AkkaConfigurationBuilder akkaBuilder)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to extend Akka.Persistence.Hosting to make it possible to register custom health checks for the JournalBuilder and SnapshotStoreBuilder

/// <param name="unHealthyStatus">The status to return when check fails. Defaults to Unhealthy.</param>
/// <param name="name">Optional name for the health check. Defaults to "Akka.Persistence.Sql.Journal.{id}.Connectivity"</param>
/// <returns>The journal builder for chaining</returns>
public static AkkaPersistenceJournalBuilder WithConnectivityCheck(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to pass in tags and have some default tags in case there are none

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant