Get SpatialOS

Sites

Menu

Game maintenance

The Deployment and Snapshot Services are in alpha and may have breaking changes before stabilizing. For more information on maturity stages see Maturity stages.

Introduction

Running regular scheduled maintenance on a game world is a common task when you have a deployment running 24 hours a day. Previously the only tools to do this were the spatial command line tool and the Console (see Scheduled maintenance). Now you can write your own automated script using the Platform SDK.

In this scenario you’ll need an active running deployment to start with, and you’ll end with a different active running deployment. For this example we’re setting up the first deployment with Setup() and stopping the second deployment with Cleanup(). You can find the full code example on GitHub.

Find out how to download the SDK from the Introduction.

Example: setting up game maintenance for a deployment

1. Instantiate clients

Instantiate clients of the DeploymentServiceClient and SnapshotServiceClient types.

Use the Create method of the DeploymentServiceClient and SnapshotServiceClient.

private static readonly DeploymentServiceClient DeploymentServiceClient = DeploymentServiceClient.Create();
private static readonly SnapshotServiceClient SnapshotServiceClient = SnapshotServiceClient.Create();

By default, it uses your refresh token saved locally by spatial CLI:

  • Windows: C:\Users\<username>\AppData\Local\.improbable\oauth2\oauth2_refresh_token\
  • Mac: ~/.improbable/oauth2/oauth2_refresh_token

If you want to provide a refresh token, you can instantiate a PlatformRefreshTokenCredential object and supply it to create:

var credentialsWithProvidedToken = new PlatformRefreshTokenCredential("my_refresh_token");
private static readonly DeploymentServiceClient DeploymentServiceClient = DeploymentServiceClient.Create(credentials: credentialsWithProvidedToken);
private static readonly SnapshotServiceClient SnapshotServiceClient = SnapshotServiceClient.Create(credentials: credentialsWithProvidedToken);

Since this example is intended to run as an automated task, we recommend using a service account for authentication. To create a service account, see Service account maintenance.

2. List deployments using the project name and deployment name

Retrieve the first deployment entry in the returned list that has the status Running and the deployment tag my_live_tag:

var currentLiveDeployment = DeploymentServiceClient
	.ListDeployments(new ListDeploymentsRequest
	{
		ProjectName = "my_project",
		DeploymentName = "my_deployment"
	})
.First(d => d.Status == Deployment.Types.Status.Running && d.Tag.Contains("my_live_tag"));

The ListDeployments RPC is paginated with a default page size of 20. You can use the optional parameter PageSize in the ListDeploymentsRequest to decrease or increase the number of records returned on each page fetch.

3. Remove my_live_tag and mark deployment as in maintenance

You can use deployment tags to identify attributes like environment (such as production or testing) or whether a deployment is part of the live game. In this case, we’re removing the tag my_live_tag to indicate that this is no longer a live deployment and players should not be directed towards it:

currentLiveDeployment.Tag.Remove("my_live_tag");

Next, set the worker flags to have a maintenance value of true or any other pairs of your choosing for a particular worker type. This lets all workers of that type in the deployment know that the deployment is entering maintenance mode and they should stop performing game updates. Send that update with a call to UpdateDeployment:

currentLiveDeployment.WorkerFlags.Add(new WorkerFlag
{
	Key = "maintenance",
	Value = "true",
	WorkerType = "unity"
});
DeploymentServiceClient.UpdateDeployment(new UpdateDeploymentRequest {Deployment = currentLiveDeployment});

4. Take a snapshot of the currently running game

This can take some time, so use the PollUntilCompleted method and wait until it’s completed:

var latestSnapshot = SnapshotServiceClient.TakeSnapshot(new TakeSnapshotRequest
{
	Snapshot = new Snapshot
	{
		ProjectName = currentLiveDeployment.ProjectName,
		DeploymentName = currentLiveDeployment.Name
	}
}).PollUntilCompleted()
.GetResultOrNull();

5. Stop the deployment using its ID and the project name

DeploymentServiceClient.StopDeployment(new StopDeploymentRequest
{
	Id = currentLiveDeployment.Id,
	ProjectName = currentLiveDeployment.ProjectName
});

The ID is a universally unique identifier for a particular run of a deployment.

6. Reuse the latest snapshot from the old deployment to start a new deployment

After cloning the deployment object, set the ID of the snapshot that was previously taken to restart at the same game state. All deployment tags and worker flags are cleared before starting the deployment to start with a clean slate. Once the deployment is up and running it can then be updated with the live tag.

var newDeployment = currentLiveDeployment.Clone();
newDeployment.StartingSnapshotId = latestSnapshot.Id;
newDeployment.Tag.Clear();
newDeployment.WorkerFlags.Clear();
newDeployment = DeploymentServiceClient
		.CreateDeployment(new CreateDeploymentRequest {Deployment = newDeployment})
		.PollUntilCompleted()
		.GetResultOrNull();

newDeployment.Tag.Add("my_live_tag");
DeploymentServiceClient.UpdateDeployment(new UpdateDeploymentRequest {Deployment = newDeployment});

You may also choose to edit the snapshot before restarting your deployment. You can do this by converting the snapshot to text and back by running spatial project history snapshot convert. You can then upload the snapshot and use it to create the new deployment.

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums