Microservices - Code

Create and deploy server-authoritative C# [CLCP-Microservices-03]

The purpose of this feature is to allow game makers to create and deploy server-authoritative C# functionality within their games.

This feature eliminates the need to build, run, and scale a game server. Game makers can create server-authoritative logic in C# inside the Unity editor.

๐Ÿ“˜

Related Guides & Video

A common use case for the feature is covered in the guides. See Adding Microservices for more info.

Example

Here a new c# server-side Microservice is created and exposes a method to be called by any c# client-side scope.

The source-code for both server-side and client-side sits local in your Unity project for efficiency and ease-of-use.

Creating a Microservice

namespace Beamable.Examples.Features.Microservices
{

  [Microservice("MyMicroservice")]
  public class MyMicroservice  : CustomMicroservice
  {
  
    [ClientCallable]
    public int GetLootboxReward()
    {
      Console.WriteLine("GetLootboxReward()");
      
      // if (IsAllowed), then reward 100 gold
      return 100;
    }
  }
}

Calling a Microservice

using Beamable;
using Beamable.Server.Clients; // don't forget this namespace

namespace Beamable.Examples.Features.Microservices
{
   public class MyMicroserviceExample : MonoBehaviour
   {
      protected async void Awake ()
      {
        var ctx = BeamContext.Default;
        await ctx.OnReady;
        var result = await ctx.Microservices().MyMicroservice().GetLootboxReward();
            
        // Result:100
        Debug.Log ($"Result:{result}");
      }
   }
}

Examples

Example: Client-Authoritative

Imagine an in-game treasure chest ("loot box") containing a random prize for the player. The player is offered the loot box as a reward for progress in the game, opens the box, and receives the prize.

In a simple game with little or no back-end technology, the prize is offered, validated, and rewarded on the client-side. This is straight-forward to code, but is relatively insecure to any malicious hackers in the gaming community.

Example: Server-Authoritative

Now imagine some portion of the loot box code is moved to the server.

Now the the prize is offered, validated, and rewarded on the server-side. This is less straight-forward to code, but is relatively secure against any malicious hackers in the gaming community.

The benefits of a server-authoritative architecture are great. There are a few major ways to set it up.

A development team could write a custom back-end server setup. This is considerable time and effort, even for experienced teams. The team could choose an off-the-shelf solution. Beamable's Microservice feature provides power and ease of use.

Example: Beamable Microservice

Let's see how Beamable can help.

Imagine some portion of loot box code is moved to the server as a Beamable Microservice.

The prize is offered, validated, and rewarded on the server-side as a Microservice. The Microservice code sits in your Unity project along-side your client side code and is written in the familiar and powerful C# language. It is straight-forward to code and it is secure against any malicious hackers in the gaming community.

Handling Errors

When a call to a Beamable service fails, it will throw a RequesterException. The exception can be caught using standard C# try/catch practices. In the example below, the call to SetCurrency will fail, and the catch block will capture a RequesterException that exposes details about the failure.

using Beamable.Common.Api;
using Beamable.Server;
using System.Threading.Tasks;

namespace Beamable.Microservices {
  [Microservice("ErrorDemo")]
  public class ErrorDemo: Microservice {
    [ClientCallable]
    public async Task < string > ServerCall() {
      try {
        // do something that will trigger a failure, like trying to reference a piece of content that doesn't exist.
        await Services.Inventory.SetCurrency("does-not-exist-so-it-will-trigger-a-400", 0);
      } catch (RequesterException ex) {
        return $ "{ex.Method.ToReadableString()} / {ex.Payload} / {ex.Prefix} / {ex.Status} / {ex.Uri} / {ex.RequestError.error} / {ex.RequestError.message} / {ex.RequestError.service}";
      }

      return "okay";
    }
  }
}

๐Ÿ“˜

Share Exception code with Unity

The RequesterException is the same type of exception that is thrown on the Unity client SDK in the event of a Beamable networking error. You can catch the same type and use the same error handling logic.

Advanced

This section contains any advanced configuration options and workflows.

Beamable & Docker

Beamable Microservices uses the industry standard Docker technology. Docker simplifies and accelerates your workflow, while giving developers the freedom to innovate with their choice of tools, application stacks, and deployment environments for each project. See Docker's documentation for more info.

Beamable handles all coordination and configuration of Docker including the beamableinc/beamservice base image hosted on Docker's DockerHub.

607607

Designing Microservices

Here are some optional, suggested Beamable data types to use along with Microservices. The Microservice can take Beamable content as input and pass Beamable player state as output. Of course, game makers may choose whatever pattern helps the specific needs of their games.

Here is a partial list of examples.

InputOutputExample
CurrencyInventoryAn RPG game client sends a request for the hero to purchase new armor. The server validates the transaction, deducts player currency and updates the player inventory
ContentObjectStatA Boss-Battle game client sends the Boss ContentObject and the Hero's Sword ContentObject. The server updates the BossHealth Stat according to the damage inflicted
List of Player MovesWinning PlayerA checkers game can validate and declare winner. The client sends a complete list of all the players' moves and the server processes the result
StatLeaderboard ScoreA platformer game client notifies that the player has completed level 3. The server validates that the user has previously completed level 1 and 2 (as required) and updates the player's high-score

Designing Microservice Methods

When designing each microservice method, a key question is 'Who is allowed access?'. Game makers control this access with Microservice method attributes.

Microservice Method Attributes

NameDetailAccessible Via?
[AdminOnlyCallable]Method callable by any admin user accountMicroservices OpenAPI
[ClientCallable]Method callable by any user accountMicroservices OpenAPI and Unity C# Client

Debugging Microservices

Development of Beamable Microservices within the Unity client is straight-forward and transparent. It is the ideal environment for development including debugging tools.

See Microservices ยป Debugging for more info.

Deploying Microservices

During development, the Microservice is run locally within a developer-specific sandbox, safely isolated from the production environment.

Using the Beamable Microservices Manager Window in the Unity Editor, the game maker can promote/deploy the Microservice to production. Choose the destination Realm and press the 'Publish' Button.

As needed, the Microservice can be rolled-back there as well.

Unity Publish Process
When Microservices and Microstorages are published from Unity, each services goes through a set of considerations and procedures. After each service has been finalized, a Service Manifest is written to the Beamable Realm that describes the desired deployment state. If the Service Manifest is not written, then no services will be updated.

Microservices may go through 3 phases before the Service Manifest is written.

  1. Build - produces a Docker image for the Microservice
  2. Verification - validates the Docker image can start and connect to Beamable. The Microservice will start during the verification step, but it will never run custom startup hooks.
  3. Upload - save the Docker image to Beamable's Docker registry

If a Microservice is disabled, and it has never been published before, then it will be skipped.
If a Microservice is disabled, and it has been published before, then the service won't be built, validated, or uploaded, but it will be included in the final Service Manifest.
If a Microservice is archived, then it will not be built, validated, or uploaded, but it will be included in the Service Manifest as archived.
If a Microservice is enabled, then it will be built, validated, and uploaded.

Microstorages only need to be built, validated, or uploaded when publishing. They only exist as entries in the Service Manifest. Microstorages don't execute custom code, so there is no need for custom images.

Deployment Size Profile

Each Microservice is given a size profile upon deployment.

Name

Detail

Benefit

Default

Small

Deployment is not scalable

Note: This is ideal for development

More economic

Medium

Deployment is partially scalable

Large

Deployment is scalable (e.g., Geographic scalability &
Load scalability)

More flexibility

โœ”๏ธ

Managing Deployed Microservices Via Portal

With the Portal, game makers can view and manage the deployed Microservices.

20952095
NameDetails
1. StatusShows the current and deploying Microservices
2. MetricsShows the metrics
3. LogsShows the logs
4. DocsShows the OpenAPI docs. See Debugging (Via OpenAPI) for more info
5. DeploymentsShows the historic deployments of Microservices
6. New DeploymentAllows game makers to make a new deployment
7. ViewAllows game makers to view new deployment

Making Beamable Calls From A Microservice

Each custom Microservice created extends the Beamable Microservice class.

This gives the custom Microservice access to key member variables:

  • Context - Refers to the current request context. It contains info including what DBID is calling and which path is run
  • Requester - It can be used to make direct (and admin privileged) requests to the rest of the Beamable Platform
  • Services - The powerful Microservice entry-point to Beamable's StatsService, InventoryService, and more

Example

Below are two versions of the same method call with varied implementations. Notice that #2 handles more functionality on the Microservice-side and is thus more secure.

#1. Method Without Beamable Services

Here the eligibility of reward is evaluated and the amount is calculated. This assumes the client side will handle the rewarding of the currency.

[ClientCallable]
public int GetLootboxReward()
{
  // if (IsAllowed), then reward 100 gold
  return 100;
}

#2. Method With Beamable Services

Here the eligibility of reward is evaluated, the amount is calculated, and the currency is rewarded.

[ClientCallable]
public async Task<bool> GetLootboxReward()
{
  // if (IsAllowed), then reward 100 gold
  await Services.Inventory.AddCurrencies(
    new Dictionary<string, long> {{"currencies.gold", 100}});

  // Optional: Return success, if needed
  return true;
}

Microservice Serialization

Unity's built-in features use Unity's serialization.

However, within a Beamable's Microservice, game makers must rely instead on Beamable's custom Serialization. This serialization is strict and has limitations.

Types

Supported TypesUnsupported Types
โ€ข Microservice Serialization Supported Typesโ€ข All other types

Request Details

When a [ClientCallable] method executes, there is an available class field, Context, that contains information about the HTTP request responsible for initiating the [ClientCallable].

Access Caller Information

It is common to require a gamerTag for several operations that take place in a Microservice. The Gamer Tag can be acquired through the Context property as the UserId. The given Gamer Tag will be the Gamer Tag for the player that initiated the request. If no Authorization header was given to the HTTP call, such as calling a [Callable] method, then the UserId may be 0, implying there is no player associated with the call.

[ClientCallable]
public void RequestDetails()
{
  var gamerTag = Context.UserId;
}

๐Ÿ“˜

Account Id

Sometimes, Beamable features require an Account Id instead of a Gamer Tag. If you need to access the Account Id of the caller, you use the GetAccountId function available from the Auth Service.

var accountId = await Services.Auth.GetAccountId();

Access Unity Version via Headers

In Beamable 1.3+, the HTTP headers can be found via the Context.Headers property. The Headers is a Dictionary<string, string>, where the keys represent HTTP header names, and the values represent HTTP header values.

The Unity Beamable SDK sends a few special headers that describe the game's environment, including the game's version, Unity's version, Beamable's version, and Unity's runtime target.

Header

Code

Description

Examples

X-KS-BEAM-SDK-VERSION

The Beamable SDK version that the request originated from.

1.3.0,
1.2.10

X-KS-USER-AGENT-VERSION

var headerPresent = Context.Headers.TryGetClientEngineVersion(out var version);

The version of the engine that sent the request.

2019.3.1,
2021.3.1

X-KS-USER-AGENT

var headerPresent = Context.Headers.TryGetClientType(out var version);

The name of the engine that sent the request.

Unity,
UnityEditor

X-KS-GAME-VERSION

var headerPresent = Context.Headers.TryGetClientGameVersion(out var version);

The version of the game that sent the request.

1.0,
0.1

These headers are sent automatically from Beamable 1.3+. If a request is sent from elsewhere, such as Portal, or a custom script, the headers may not be present.

UseLegacySerialization

A breaking change is introduced in Beamable SDK v0.11.0. If you began your project with an earlier version of the SDK, see Beamable Releases Unity SDK Version 0.11.0 for more info. Otherwise, simply disregard this issue.


Did this page help you?