Connectivity - Code - Reduce NoConnectivityException

A few noteworthy clarifications:

  1. There are two services responsible for connectivity:
    1. ConnectivityChecker: This service implements the call that determines whether Beamable is reachable.
    2. ConnectivityService: This service maintains the state on whether internet connectivity is currently available, and is also responsible for invoking any reconnect hooks and so forth
  2. The NoConnectivityException errors can occur as a result of a couple of conditions:
    1. The ConnectivityChecker, which checks connectivity every 3 seconds, experiences a failure OR
    2. A request to Beamable experiences a timeout or HTTP status code 0 from Unity
      Beamable also makes regular heartbeat calls which may also fall into this class
  3. When a NoConnectivityException is encountered, the ConnectivityService is notified that the internet connection has been lost, and the ConnectivityService then invokes any relevant hooks for reconnecting when the service is restored.

As such, this can result in false negatives (the ConnectivityService erroneously reports that connectivity has been lost if a single request, which may not be critical to the game, results in a timeout).

The below changes (dependency registration and connectivity service override) alter this behavior:

  • ConnectivityChecker has been stubbed to always report that internet connectivity is available
  • ConnectivityService has also been stubbed to always report that internet connectivity is available
  • You can also update the Project Settings to:
    • Disable offline cache
    • Disable sending heartbeat
      • If you're using Beamable matchmaking, you want to keep this on.
    • Disable optimistic inventory updates

The result of this is as follows:

  • When a request times out or results in a status code 0 -- it will not cause the ConnectivityService to declare that the internet connectivity is unavailable. That specific request will still result in a NoConnectivityException , so you can retry it if you choose, but it will not cascade into other requests.
  • Beamable will no longer phone home frequently (heartbeat), resulting in noisy numbers of errors in case of a dropped connection

Overall, users with bad connections will see an error, as they should, but people with fine connections should experience markedly fewer false negatives.

Dependency Registration

[BeamContextSystem]
public class DependencyRegistration
{
  [RegisterBeamableDependencies]
  public static void Register(IDependencyBuilder builder)
  {
    builder.ReplaceSingleton<IConnectivityChecker, AlwaysConnectivityChecker>();
    builder.ReplaceSingleton<IConnectivityService, AlwaysConnectivityService>();
    Debug.Log("Registered custom Beamable dependencies.");
  }
}

Connectivity Service Override

public class AlwaysConnectivityChecker : IConnectivityChecker
{
  public bool ConnectivityCheckingEnabled { get; set; } = false;

  public Promise<bool> ForceCheck()
  {
    return Promise<bool>.Successful(true);
  }
}

public class AlwaysConnectivityService : IConnectivityService
{
  public Promise SetHasInternet(bool hasInternet)
  {
    // SetHasInternet(true) gets called frequently, so not logging it here.
    if (!hasInternet)
    {
      Debug.Log("Ignoring SetHasInternet(false) in AlwaysConnectivityService");
    }
    return Promise.Success;
  }

  public Promise ReportInternetLoss()
  {
    // ReportInternetLoss may be overly verbose, so this Debug.Log is commented out.
    // Debug.Log("Ignoring ReportInternetLoss in AlwaysConnectivityService");
    return Promise.Success;
  }

  public void OnReconnectOnce(Action onReconnection)
  {
    Debug.Log("Immediately calling Action for OnReconnectOnce in AlwaysConnectivityService");
    onReconnection();
  }

  public void OnReconnectOnce(ConnectionCallback promise, int order = 0)
  {
    Debug.Log("Immediately calling ConnectionCallback for OnReconnectOnce in AlwaysConnectivityService");
  }

  public bool HasConnectivity => true;
  public bool ForceDisabled
  {
    get => false;
    set => Debug.Log("Ignoring ForceDisabled.set in AlwaysConnectivityService");
  }

  public bool Disabled => false;

  // In AlwaysConnectivityService, we never invoke OnConnectivityChanged.
  public event Action<bool> OnConnectivityChanged;
}