Creating a Resilient Service

A Resilient Service implements IConnectable, integrating with Altruist's startup lifecycle for automatic connection management, retry logic, and health monitoring.

Implementing IConnectable

[Service(typeof(IConnectable))]
public class MyExternalService : IConnectable
{
    private bool _connected;
    private int _connectionAttempts;

    public string ServiceName => "MyExternalService";
    public bool IsConnected => _connected;

    public event Action? OnConnected;
    public event Action<Exception>? OnFailed;
    public event Action<Exception>? OnRetryExhausted;

    public async Task ConnectAsync(int maxRetries = 30, int delayMilliseconds = 2000)
    {
        _connected = false;
        _connectionAttempts = 0;

        while (!_connected && _connectionAttempts < maxRetries)
        {
            _connectionAttempts++;
            try
            {
                // Real connection logic goes here (e.g., connect to message broker)
                await Task.Delay(delayMilliseconds);

                _connected = true;
                RaiseConnectedEvent();
                return;
            }
            catch (Exception ex)
            {
                RaiseFailedEvent(ex);
            }
        }

        if (!_connected)
        {
            // Irreversible error — Altruist will shut down the server
            RaiseOnRetryExhaustedEvent(new Exception("Max retries reached."));
        }
    }

    public void RaiseConnectedEvent() => OnConnected?.Invoke();
    public void RaiseFailedEvent(Exception ex) => OnFailed?.Invoke(ex);
    public void RaiseOnRetryExhaustedEvent(Exception ex) => OnRetryExhausted?.Invoke(ex);
}

The [Service(typeof(IConnectable))] attribute is all that's needed — Altruist auto-discovers the service and calls ConnectAsync() during startup.

Note:

This is what makes it truly resilient — Altruist auto-discovers and monitors the service during startup, handling the connection lifecycle for you.

What Happens

  • During app startup, Altruist calls ConnectAsync() on all IConnectable services
  • The service retries connection attempts based on maxRetries and delayMilliseconds
  • On success, OnConnected fires
  • If all retries fail, OnRetryExhausted fires and the app shuts down gracefully

Use Cases

This structure makes it easy to create services for:

  • External databases or caches
  • Game-specific third-party APIs
  • Gateways or message brokers (e.g., Kafka, NATS)
  • Monitoring or analytics services

Note:

Database providers (IGeneralDatabaseProvider) already extend IConnectable, so they get resilient connection handling automatically — no extra registration needed.