メインコンテンツまでスキップ

Websocket Reconnection Strategy

Last updated on December 17, 2024

Overview

The AccelByte Gaming Services (AGS) Game SDK allows game developers to implement WebSocket reconnection with strategy based on specific needs. This strategy will apply to all WebSocket services, including Lobby, Chat, AMS, and DSHub. The default recommendation for the strategy is already set, and the configuration can be updated within the game level code.

See below to learn more about the different strategies offered:

BALANCEDAGGRESSIVELIMITLESS
Retry to reconnect with a balance retry interval until the specified timed out duration.Retry to reconnect with an aggressive retry interval until the specified timed out duration.Always retry to reconnect until the connection is fulfilled.
Default reconnect delay pattern:
- initial backoff delay: 1s
- backoff base factor: 2
- balanced max retry interval: 30s

~1, ~2, ~4, ~8, ~16, ~30, ~30, … until timed out
Default reconnect delay pattern:
- aggressive retry interval: 3s

~3, ~3, ~3, ~3, … until timed out
Default reconnect delay pattern:
- initial backoff delay: 1s
- backoff base factor: 2
- max retry interval: 120s

~1, ~2, ~4, 8, ~16, ~32, ~64, ~120, ~120, … no timed out
Recommended for client WebSocket reconnection.Recommended for client WebSocket reconnection with an aggressive method.Recommended for server WebSocket reconnection.
The strategy is set as default for Lobby and Chat WebSocket.-The strategy is set as default for AMS and DSHub WebSocket

Implementation

This guideline is to configure and modify WebSocket configuration for the Lobby service, but it will also apply the same for other services like Chat, AMS, and DSHub.

Get WebSocket strategy configuration

You can get the WebSocket strategy configuration from the AGS OSS using the TryConfigureWebsocketConnection function. Specify the LocalUserNum and target WebsocketServiceType to the function parameter. The WebSocket service type contains values such as these: LOBBY_GAMECLIENT, CHAT_GAMECLIENT, DS_HUB_GAMESERVER, and AMS_GAMESERVER.

FOnlineSubsystemAccelByte* OnlineSubsystemAccelByte = static_cast<FOnlineSubsystemAccelByte*>(IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM));

// Obtain configurable WebSocket interface of AGS Lobby
TOptional<IWebsocketConfigurableReconnectStrategy*> LobbyWebsocketConfiguration = OnlineSubsystemAccelByte->TryConfigureWebsocketConnection(LocalUserNum, AccelByte::EConfigurableWebsocketServiceType::LOBBY_GAMECLIENT);

// Check WebSocket interface configuration
if (!LobbyWebsocketConfiguration.IsSet())
{
// AGS Lobby WebSocket configuration is not valid
return false;
}

Create a balanced reconnect strategy

You can use the FReconnectionStrategy class to call CreateBalancedStrategy to create a reconnection strategy. In the creation of a balanced strategy, you can specify three parameters, such as:

  • FBalancedMaxRetryInterval - Specify maximum retry interval. The default value is 30 seconds.
  • FTotalTimeoutDuration - Specify the timed out duration to reconnect. The default value is 60 seconds.
  • FInitialBackoffDelay - Specify the initial duration time to start at first reconnect. The default value is 1 second.
FReconnectionStrategy::FBalancedMaxRetryInterval BalancedMaxRetryInterval = FReconnectionStrategy::FBalancedMaxRetryInterval(
FTimespan::FromSeconds(60.0f)
);
FReconnectionStrategy::FTotalTimeoutDuration TotalTimeoutDuration = FReconnectionStrategy::FTotalTimeoutDuration(
FTimespan::FromSeconds(120.0f)
);
FReconnectionStrategy::FInitialBackoffDelay InitialBackoffDelay = FReconnectionStrategy::FInitialBackoffDelay(
FTimespan::FromSeconds(5.0f)
);
FReconnectionStrategy BalancedReconnectStrategy = FReconnectionStrategy::CreateBalancedStrategy(
BalancedMaxRetryInterval, TotalTimeoutDuration, InitialBackoffDelay
);

Create an aggressive reconnect strategy

You can use the FReconnectionStrategy class to call CreateAggressiveStrategy to create a reconnection strategy. In the creation of an aggressive strategy, you can specify three parameters, such as:

  • FAggressiveRetryInterval - Specify the reconnect delay interval. The default value is 3 seconds.
  • FTotalTimeoutDuration - Specify the timed out duration to reconnect. The default value is 20 seconds.
  • FInitialBackoffDelay - Specify the initial duration time to start at first reconnect. The default value is 1 second.
FReconnectionStrategy::FAggressiveRetryInterval AggressiveRetryInterval = FReconnectionStrategy::FAggressiveRetryInterval(
FTimespan::FromSeconds(5.0f)
);
FReconnectionStrategy::FTotalTimeoutDuration TotalTimeoutDuration = FReconnectionStrategy::FTotalTimeoutDuration(
FTimespan::FromSeconds(120.0f)
);
FReconnectionStrategy::FInitialBackoffDelay InitialBackoffDelay = FReconnectionStrategy::FInitialBackoffDelay(
FTimespan::FromSeconds(120.0f)
);
FReconnectionStrategy AggressiveReconnectStrategy = FReconnectionStrategy::CreateAggressiveStrategy(
AggressiveRetryInterval, TotalTimeoutDuration, InitialBackoffDelay
);

Create a limitless reconnect strategy

You can use the FReconnectionStrategy class to call CreateLimitlessStrategy to create a reconnection strategy. In the creation of a limitless strategy, you can specify this parameter:

  • FInitialBackoffDelay - Specify the initial duration time to start at first reconnect. The default value is 1 second.
FReconnectionStrategy::FInitialBackoffDelay InitialBackoffDelay = FReconnectionStrategy::FInitialBackoffDelay(
FTimespan::FromSeconds(120.0f)
);
FReconnectionStrategy LimitlessReconnectStrategy = FReconnectionStrategy::CreateLimitlessStrategy(
InitialBackoffDelay
);

Update the base factor of the backoff mechanism

You can set or update the base factor of the backoff mechanism based on your needs. If you set the base factor to 4s, then the reconnect delay pattern should look like this:

~1, ~4, ~16, ~64, …

constexpr uint32 BASE_FACTOR = 4;
auto BalancedStrategy = FReconnectionStrategy::CreateBalancedStrategy();
BalancedStrategy.SetBackoffMechanism(BASE_FACTOR);

Set the default reconnection strategy

After the creation of the reconnect strategy, you can set the default strategy. You can use the LobbyWebsocketConfiguration variable that you created to call the SetDefaultReconnectionStrategy function. The function parameter should be the reconnect strategy that you created earlier; it is either a balanced, an aggressive, or a limitless strategy.

Setting up a balanced reconnect strategy:

LobbyWebsocketConfiguration.GetValue()->SetDefaultReconnectionStrategy(BalancedReconnectStrategy);

Setting up an aggressive strategy:

LobbyWebsocketConfiguration.GetValue()->SetDefaultReconnectionStrategy(AggressiveReconnectStrategy);

Setting up a limitless strategy:

LobbyWebsocketConfiguration.GetValue()->SetDefaultReconnectionStrategy(LimitlessReconnectStrategy);

Set a specific reconnection strategy

You also can specify the reconnection strategy for various target disconnection closure types. You can set this up using the SetSpecificReconnectionStrategy function. The function parameter also contains the WebSocket closure code such as:

  • ClosedAbnormally - WebSocket disclosure code 1006
  • DisconnectServerShutdown - WebSocket disclosure code 4000
LobbyWebsocketConfiguration.GetValue()->SetSpecificReconnectionStrategy(
AccelByte::EWebsocketClosureCodeForSpecificRetry::ClosedAbnormally, //1006 code
AggressiveReconnectStrategy
);
LobbyWebsocketConfiguration.GetValue()->SetSpecificReconnectionStrategy(
AccelByte::EWebsocketClosureCodeForSpecificRetry::DisconnectServerShutdown, //4000 code
LimitlessReconnectStrategy
);

Update massive outage duration

You can specify the duration of a massive outage and it will be used to notify a callback and provide some additional information for various needs. A massive outage callbacks is only received if the reconnection attempt is not exhausted or has not given up yet.

If you set the massive outage seconds to 40, then it will notify the massive outage callback every 40 seconds if the reconnection attempt is not exhausted. Refer to the set up delegate section for the callback delegation overview.

constexpr uint32 MASSIVE_OUTAGE_SETTING_SECONDS = 40;
LobbyWebsocketConfiguration.GetValue()->GetDefaultReconnectionStrategy().SetMassiveOutageDuration(FTimespan::FromSeconds(MASSIVE_OUTAGE_SETTING_SECONDS));

Set up callback delegate of reconnection strategy

You will provide a delegate callback to notify the game if the WebSocket is currently reconnecting and passing additional information for various needs. There are two delegates that you will introduce for the reconnection strategy, such as:

- `ReconnectAttempted` - This delegate will fire when trying to reconnect.
- `MassiveOutage` - This delegate will always fire when the massive outage duration is fulfilled. Massive outages are only received if the reconnection attempt is not exhausted or has given up yet.

Lobby service

You can use the Identity Interface and then call the delegate to start registering callbacks, such as:

  • AddAccelByteOnLobbyReconnectAttemptedDelegate_Handle
    • Specify the LocalUserNum parameter for the current local player controller.
    • Create a lambda of FAccelByteOnLobbyReconnectAttemptedDelegate.
  • AddAccelByteOnLobbyMassiveOutageEventDelegate_Handle
    • Specify the LocalUserNum parameter for the current local player controller.
    • Create a lambda of FAccelByteOnLobbyMassiveOutageEventDelegate.
TSharedPtr<FOnlineIdentityAccelByte, ESPMode::ThreadSafe> IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(OnlineSubsystemAccelByte->GetIdentityInterface());
if (!IdentityInterface.IsValid())
{
return false;
}

FDelegateHandle ReconnectAttemptedHandle = IdentityInterface->AddAccelByteOnLobbyReconnectAttemptedDelegate_Handle(
LocalUserNum, FAccelByteOnLobbyReconnectAttemptedDelegate::CreateLambda([&](int32 /*LocalUserNum*/, const FReconnectAttemptInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("ReconnectAttempt! AttemptCount %d, NextRetry %s"), Info.AttemptCount, *Info.NextRetryAttemptIn.ToString());
}));

FDelegateHandle MassiveOutageHandle = IdentityInterface->AddAccelByteOnLobbyMassiveOutageEventDelegate_Handle(
LocalUserNum, FAccelByteOnLobbyMassiveOutageEventDelegate::CreateLambda([&](int32 /*LocalUserNum*/, const FMassiveOutageInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("MassiveOutage! TotalTimeoutDuration %s"), *Info.TotalTimeoutDuration.ToString());
}));

Chat service

You can use Chat Interface and then call the delegate to start registering callbacks, such as:

  • AddAccelByteOnChatReconnectAttemptedDelegate_Handle
    • Specify the LocalUserNum parameter for the current local player controller.
    • Create a lambda of FAccelByteOnChatReconnectAttemptedDelegate.
  • AddAccelByteOnChatMassiveOutageEventDelegate_Handle
    • Specify the LocalUserNum parameter for the current local player controller.
    • Create a lambda of FAccelByteOnChatMassiveOutageEventDelegate.
TSharedPtr<FOnlineChatAccelByte, ESPMode::ThreadSafe> ChatInterface = StaticCastSharedPtr<FOnlineChatAccelByte>(OnlineSubsystemAccelByte->GetChatInterface());
if (!ChatInterface.IsValid())
{
return false;
}

FDelegateHandle ReconnectAttemptedHandle = ChatInterface->AddAccelByteOnChatReconnectAttemptedDelegate_Handle(
LocalUserNum, FAccelByteOnChatReconnectAttemptedDelegate::CreateLambda([&](int32 /*LocalUserNum*/, const FReconnectAttemptInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("ReconnectAttempt! AttemptCount %d, NextRetry %s"), Info.AttemptCount, *Info.NextRetryAttemptIn.ToString());
}));

FDelegateHandle MassiveOutageHandle = ChatInterface->AddAccelByteOnChatMassiveOutageEventDelegate_Handle(
LocalUserNum, FAccelByteOnChatMassiveOutageEventDelegate::CreateLambda([&](int32 /*LocalUserNum*/, const FMassiveOutageInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("MassiveOutage! TotalTimeoutDuration %s"), *Info.TotalTimeoutDuration.ToString());
}));

AMS service

You can use the Session V2 Interface and then call the delegate to start registering callbacks, such as:

  • AddAccelByteOnAMSReconnectAttemptedDelegate_Handle
    • Create a lambda of FAccelByteOnAMSReconnectAttemptedDelegate.
  • AddAccelByteOnAMSMassiveOutageEventDelegate_Handle
    • Create a lambda of FAccelByteOnAMSMassiveOutageEventDelegate.
TSharedPtr<FOnlineSessionV2AccelByte, ESPMode::ThreadSafe> SessionInterface = StaticCastSharedPtr<FOnlineSessionV2AccelByte>(OnlineSubsystemAccelByte->GetSessionInterface());
if (!SessionInterface.IsValid())
{
return false;
}

FDelegateHandle ReconnectAttemptedHandle = SessionInterface->AddAccelByteOnAMSReconnectAttemptedDelegate_Handle(FAccelByteOnAMSReconnectAttemptedDelegate::CreateLambda([&](const FReconnectAttemptInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("ReconnectAttempt! AttemptCount %d, NextRetry %s"), Info.AttemptCount, *Info.NextRetryAttemptIn.ToString());
}));

FDelegateHandle MassiveOutageHandle = SessionInterface->AddAccelByteOnAMSMassiveOutageEventDelegate_Handle(FAccelByteOnAMSMassiveOutageEventDelegate::CreateLambda([&](const FMassiveOutageInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("MassiveOutage! TotalTimeoutDuration %s"), *Info.TotalTimeoutDuration.ToString());
}));

DSHub service

You can use the Session V2 Interface and then call the delegate to start registering callbacks, such as:

  • AddAccelByteOnDSHubReconnectAttemptedDelegate_Handle
    • Create a lambda of FAccelByteOnDSHubReconnectAttemptedDelegate.
  • AddAccelByteOnDSHubMassiveOutageEventDelegate_Handle
    • Create a lambda of FAccelByteOnDSHubMassiveOutageEventDelegate.
TSharedPtr<FOnlineSessionV2AccelByte, ESPMode::ThreadSafe> SessionInterface = StaticCastSharedPtr<FOnlineSessionV2AccelByte>(OnlineSubsystemAccelByte->GetSessionInterface());
if (!SessionInterface.IsValid())
{
return false;
}

FDelegateHandle ReconnectAttemptedHandle = SessionInterface->AddAccelByteOnDSHubReconnectAttemptedDelegate_Handle(FAccelByteOnDSHubReconnectAttemptedDelegate::CreateLambda([&](const FReconnectAttemptInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("ReconnectAttempt! AttemptCount %d, NextRetry %s"), Info.AttemptCount, *Info.NextRetryAttemptIn.ToString());
}));

FDelegateHandle MassiveOutageHandle = SessionInterface->AddAccelByteOnDSHubMassiveOutageEventDelegate_Handle(FAccelByteOnDSHubMassiveOutageEventDelegate::CreateLambda([&](const FMassiveOutageInfo& Info)
{
UE_LOG(LogTemp, Log, TEXT("MassiveOutage! TotalTimeoutDuration %s"), *Info.TotalTimeoutDuration.ToString());
}));