Fleet Service Migration Guide #

Pragma Engine version 0.0.97 introduces the Fleet service, a service for processing game instance requests and coordinating with third-party game server management providers to allocate game servers. The Fleet service is intended to eventually replace the existing Match Capacity service, although both services are currently available.

This guide is intended to help current Match Capacity users migrate to using the Fleet service. For detailed information about the Fleet service, see the Fleet service documentation.

Fleet service introduction #

The new Fleet service allows users to better manage their fleet of game servers. Through the introduction of server pools, the Fleet service allows you to manage homogenous groups of servers for different contexts. The Fleet service automatically manages game server capacity by server pool, based on defined management policies. With these features you no longer have to manually track capacity.

Overview of Tasks #

Update class references #

Change classes that extend MatchCapacityProvider to instead extend FleetPlugin, updating the interface appropriately (see Implement the Fleet Plugin Methods).

Update configuration values #

To take advantage of the Fleet service features, such as server pools and server pool management policies, add/update configuration blocks and values in your YAML configuration file.

Migrate MatchCapacityConfig values to ServerPoolManagementPolicies #

The Fleet service allows you to define various server pool management policies that you can apply to one or more server pools (groups of game servers). To take advantage of this capability, migrate the data in the MatchCapacityServiceConfig matchCapacityConfig configuration block to a serverPoolManagementPolicies block in the FleetServiceConfig section, giving it an id of defaultPoolManagementPolicy:

Before: Sample MatchCapacityServiceConfig configuration data

MatchCapacityServiceConfig:
    matchCapacityConfig:
    floor: 0
    ceiling: 10
    headroomPercent: 0
    serverMaxStartDurationMillis: 120000
    serverHeartbeatPeriodMillis: 1000
    serverHeartbeatExpiryFactor: 5.0
    gameCapacityResolvedTimeoutMillis: 30000

After: Sample FleetServiceConfig configuration data after migrating and configuring a default server pool management policy

game:
  serviceConfigs:
    FleetServiceConfig:
      serverPoolManagementPolicies:
   1:
     id: "defaultPoolManagementPolicy"
     gameCapacityPerServer: 1
     capacityFloor: 0
     capacityCeiling: 10
     capacityBuffer: 40
     serverMaxStartDurationMillis: 120000
     serverHeartbeatPeriodMillis: 1000
     serverHeartbeatExpiryFactor: 5.0
     gameCapacityResolvedTimeoutMillis: 30000

Note the following values were updated/added:

OldNewDescription
N/AidUnique identifier for the server pool management policy
N/AgameCapacityPerServerNumber of game instances this server can host at a given time
floorcapacityFloorMinimum game capacity allocated at all times
ceilingcapacityCeilingMaximum game capacity allocated at all times
headroomPercentcapacityBufferPreferred available game capacity defined as a percentage of used game capacity

Migrate LocalProcessCapacityProvider configuration values to LocalProcessFleetPlugin #

If currently using the LocalProcessCapacityProvider, move the configuration values in the matchcapacity.LocalProcessCapacityProvider class to the fleet.LocalProcessFleetPlugin class, as shown in the following example:

In addition, the Fleet service includes three updated/new configuration values:

OldNewDescription
serverIdParam: -serverId=serverIdParam: -gameServerId=Game server ID
gameServerZoneParam: -gameServerZone=RemovedN/A
N/AserverPoolIdParam: -serverPoolId=Server pool ID for the server
N/AserverPoolConfigs:Config blocks for various server pools, including values such as server pool ID, associated management policy, and game server versions

Before: Sample LocalProcessCapacityProvider configuration

    MatchCapacityService.capacityProvider:
      class: "pragma.matchcapacity.LocalProcessCapacityProvider"
      config:
        processCommand:
          0: "path/to/your/built/unity/Server.exe"
          1: -pragmaBackendAddress="http://127.0.0.1:10100"
          2: -hostname="127.0.0.1"
          3: -port=9999
          4: -version="GameServerVersion1"
          # 5: -pragmaServerNoExit        
        serverIdParam: -serverId=
        gameServerZoneParam: -gameServerZone=
        logPathParam: ""
        logOutputPath: ""
        maximumLocalServers: 1

After: Sample LocalProcessFleetPlugin configuration

FleetService.fleetPlugin:
    class: "pragma.fleet.LocalProcessFleetPlugin"
    config:
    processCommand:
        0: "path/to/your/built/unity/Server.exe"
        1: -pragmaBackendAddress="http://127.0.0.1:10100"
        2: -hostname="127.0.0.1"
        3: -port=9999
        4: -version="GameServerVersion1"
        # 5: -pragmaServerNoExit
    serverIdParam: -gameServerId=                        
    serverPoolIdParam: -serverPoolId=                    
    logPathParam: "" # these don't do anything in unity
    logOutputPath: "" # these don't do anything in unity
    maximumLocalServers: 1
    serverPoolConfigs:                                 
        0:
        serverPoolId: "LocalServerPool"
        managementPolicyConfigId: "LocalDevelopment"
        gameServerVersions:
            0: "myLocalServerVersion"
The LocalProcessFleetPlugin allows for configuring multiple server pools and will use the game server version to decide which server pool to return when selectServerPool is called. This means that a single game server version should not appear on more than one gameServerVersions list.

Migrate PragmaNomadCapacityProvider configuration values to NomadFleetPlugin #

If currently using the PragmaNomadCapacityProvider, move the configuration values in the matchcapacity.PragmaNomadCapacityProvider class to the fleet.NomadFleetPlugin class, as shown in the following example.

Before: Sample PragmaNomadCapacityProvided configuration

MatchCapacityService.capacityProvider:
    class: "pragma.matchcapacity.PragmaNomadCapacityProvider"
    config:
    url: "https://nomad.playtest.internal.arbiter.arbiterstudios.pragmaengine.com"
    jobDatacenter: "us-west-2"
    executableName: "ServerLinux"
    capacityPerServer: 64
    args:
        0: -pragmaBackendAddress="https://playtest.arbiter.arbiterstudios.pragmaengine.com:10100"
        1: -server
        2: -pragmaDebug=0
        3: -gameServerZone="UsWest"
        4: -batchmode
        5: -nographics

After: Sample NomadFleetPlugin configuration

FleetService.fleetPlugin:
    class: "pragma.fleet.NomadFleetPlugin"
    config:
    url: "https://nomad.playtest.internal.arbiter.arbiterstudios.pragmaengine.com"
    jobDatacenter: "us-west-2"
    executableName: "ServerLinux"
    capacityPerServer: 64
    args:
        0: -pragmaBackendAddress="https://playtest.arbiter.arbiterstudios.pragmaengine.com:10100"
        1: -server
        2: -pragmaDebug=0
        3: -gameServerZone="UsWest"
        4: -batchmode
        5: -nographics

Migrate MultiplayCapacityProvider to MultiplayFleetPlugin #

If currently using the MultiplayCapacityProvider (for environments using Unity Game Server Hosting Multiplay), move the configuration values in the matchcapacity.MultiplayCapacityProvider class to the fleet.MultiplayFleetPlugin class, as shown in the following example.

The serverPoolId, profileId, and regionId configured in each ServerPoolConfig block should be unique to that server pool so that the plugin can map Multiplay region IDs to a unique Multiplay profile ID when allocating game servers. This allows for configuring your Multiplay profile IDs per region.

Before: Sample MultiplayCapacityProvider configuration

MatchCapacityService.capacityProvider:
  class: "pragma.matchcapacity.MultiplayCapacityProvider"
  config:
    capacityPerServer: 1
    regionId: "2222a2a2-a22a-22a2-a2a2-2a222aa22222"
    fleetId: "1111a1a1-a11a-11a1-a1a1-1a111aa11111"
    projectGuid: "1111b1b1-b11b-11b1-b1b1-1b111bb11111"
    profileId: "1234567"
    accessKey: "YOUR_ACCESS_KEY"       
    secretAccessKey: "YOUR_SECRET_ACCESS_KEY_THAT_HAS_BEEN_ENCRYPTED_BY_PRAGMA"
    useAllocateV2: true
    pragmaGamePartnerBackendAddress: "http://somehost.net:10100"
    gameServerZoneToMultiplayRegionId:
      UsWest: "1111a1a1-a11a-11a1-a1a1-1a111aa11111"
      UsEast: "2222a2a2-a22a-22a2-a2a2-2a222aa22222"
      Europe: "3333a3a3-a33a-33a3-a3a3-3a333aa33333"
      Korea: "4444a4a4-a44a-44a4-a4a4-4a444aa44444"

After: Sample MultiplayFleetPlugin configuration

FleetService.fleetPlugin:
  class: "pragma.fleet.MultiplayFleetPlugin"
  config:
    capacityPerServer: 1
    fleetId: "1111a1a1-a11a-11a1-a1a1-1a111aa11111"       
    projectGuid: "1111b1b1-b11b-11b1-b1b1-1b111bb11111"      
    accessKey: "YOUR_ACCESS_KEY"
    secretAccessKey: "YOUR_SECRET_ACCESS_KEY_THAT_HAS_BEEN_ENCRYPTED_BY_PRAGMA"
    useAllocateV2: true
    pragmaGamePartnerBackendAddress: "http://somehost.net:10100"
    gameServerZoneToMultiplayRegionId:
      UsWest: "1111a1a1-a11a-11a1-a1a1-1a111aa11111"
      UsEast: "2222a2a2-a22a-22a2-a2a2-2a222aa22222"
      Europe: "3333a3a3-a33a-33a3-a3a3-3a333aa33333"
      Korea: "4444a4a4-a44a-44a4-a4a4-4a444aa44444"
    serverPoolConfigs:
      0:
        serverPoolId: "3v3_UsWest"
        managementPolicyConfigId: "3v3_LowPop"
        profileId: "1234567" # First Profile Id
        regionId: "1111a1a1-a11a-11a1-a1a1-1a111aa1111" # UsWest
      1:
        serverPoolId: "3v3_UsEast"
        managementPolicyConfigId: "3v3_HighPop"
        profileId: "7654321" # Second Profile Id
        regionId: "2222a2a2-a22a-22a2-a2a2-2a222aa22222" # UsEast
The MultiplayFleetPlugin will no longer send the gameServerZone, but instead send the pragmaBackendAddress and serverPoolId values in the AllocateV2 request body payload. Provide the serverPoolId value to the MatchApi.StartReportCapacityPolling method to ensure Pragma can properly track the allocated server.

Implement the Game Instance Host Plugin Method #

The new Game Instance Host Plugin contains the findHostForGameInstance method, which populates the ExtHostRequest. The ExtHostRequest is used in the Fleet service to determine which server pool to assign for the game instance.

fun findHostForGameInstance(
  gameInstance: GameInstance, 
): ExtHostRequest?

If you choose to not use Pragma’s Fleet service and instead want to manage your fleet outside of Pragma, return null. Use this method to integrate with your game server provider in order to allocate a game server for this game instance.

Implement the Fleet plugin methods #

The new Fleet Plugin contains the add method formerly handled by the Capacity Provider, as well as new selectServerPool and getServerPoolById methods.

Migrate CapacityProvider.add capabilities to to FleetPlugin.add #

If the Fleet service determines that the current available capacity cannot fulfill a request to create a game instance in a given server pool, the Fleet Plugin’s add() method is called to generate additional capacity onto the service.

The new Fleet Plugin add() method simplifies the Capacity Provider’s add process in the following ways:

  • You no longer need to calculate the number of game servers to spin up or to create server IDs. The add() method is provided with a list of Pragma-generated server IDs (allocation: List <UUID>) that you can use to spin up game servers (one game server for each game server ID in the allocations list).
  • You can use the serverPool object, which includes the server pool ID, the management policy ID, and the ExtServerPool payload, to specific game servers according to values.

Move custom functionality from your CapacityProvider.add implementation to your FleetPlugin.add implementation:

Before: Sample CapacityProvider add method implementation

override suspend fun add(
    gameVersion: String,
    gameServerZone: String,
    extraMatchCapacity: Int,
    capacityTracker: CapacityTracker
) {
    val partnerGameAuthToken = tokenSignerNodeService.createPartnerGameToken(
        service.pragmaNode.pragmaConfig.core.shardId
    )
    val partnerSocialAuthToken = tokenSignerNodeService.createPartnerSocialToken()

    val requiredServerCount = calculatServerCount(
        extraMatchCapacity,
        config.capacityPerServer
    )
    repeat(requiredServerCount) {
        val serverId = capacityTracker.addNewServer(
            gameVersion,
            gameServerZone,
            config.capacityPerServer
        )

        val configArgs = config.args.entries
            .sortedBy { it.key }
            .map { it.value }
            .toMutableList()

        val dispatchRequest = mapOf(
            META to mapOf(
                ARGS to configArgs,
                EXECUTABLE_NAME to config.executableName,
                PARTNER_GAME_AUTH_TOKEN to partnerGameAuthToken,
                PARTNER_SOCIAL_AUTH_TOKEN to partnerSocialAuthToken,
                SERVER_ID to serverId,
                VERSION to gameVersion,
            )
        )

        dispatchRequestToGameServerProvider(
            dispatchRequest,
            serverId,
            capacityTracker
        )
    }

}

After: Sample FleetPlugin add method implementation

override suspend fun add(serverPool: ServerPool, allocations: List<UUID>) {
    val partnerGameAuthToken = tokenSignerNodeService.createPartnerGameToken(
        service.pragmaNode.pragmaConfig.core.shardId
    )
    val partnerSocialAuthToken = tokenSignerNodeService.createPartnerSocialToken()
    
    allocations.forEach { serverId ->
        val configArgs = config.args.entries
            .sortedBy { it.key }
            .map { it.value }
            .toMutableList()

        val dispatchRequest = mapOf(
            META to mapOf(
                ARGS to configArgs,
                EXECUTABLE_NAME to config.executableName,
                PARTNER_GAME_AUTH_TOKEN to partnerGameAuthToken,
                PARTNER_SOCIAL_AUTH_TOKEN to partnerSocialAuthToken,
                SERVER_ID to serverId,
                SERVER_POOL_ID to serverPool.serverPoolId,
            )
        )

        dispatchRequestToGameServerProvider(dispatchRequest)
    }
}

Implement selectServerPool and getServerPoolById #

The new Fleet Plugin selectServerPool() method determines what server pool a given game instance should be associated with, ensuring the game instance finds an appropriate game server to run on. See our documentation for instructions on customizing the selectServerPool method.

The Fleet Plugin getSeverPoolById() method determines what server pool should be used when given a ServerPool.serverPoolId. This is used as a fallback if your game server reports a server id that is unrecognized by Pragma. This situation can occur when you are using a local game server not allocated using the Fleet service. The Fleet service executes this when Pragma is unable to reconcile a server pool for a game server that is reporting capacity.

If your plugin needs to access the gameServerVersion and gameServerZone in the add() method, be sure to include it on the ExtServerPool returned from selectServerPool.

Update SDK calls #

Ensure you are calling the correct StartReportCapacityPolling SDK method, which contains the following parameters:

  • ServerId - ID for the server that should start reporting its capacity. This value will be provided by the Fleet Plugin add function, and should be passed to the game server provider as it spins up the server.
  • ServerPoolId - Server Pool ID for the server that should start reporting its capacity. This value will be provided by the Fleet Plugin add function, and should be passed to the game server provider as it spins up the server.
  • Timeout - Defines how long to wait for the first game allocation to the game server. If you do not want to use the timeout, provide a value of 0 for the timeout parameter.
  • MaxGameInstanceCount - Number of game instances that can run on this server. This value should match your configured gameCapacityPerServer. Default is 1.