Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gamelift): add MatchmakingRuleSet L2 Construct for GameLift #23091

Merged
merged 6 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 69 additions & 2 deletions packages/@aws-cdk/aws-gamelift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,73 @@ deliver inexpensive, resilient game hosting for your players
This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. It allows you to define components for your matchmaking
configuration or game server fleet management system.

## GameLift FlexMatch

### Matchmaking RuleSet

Every FlexMatch matchmaker must have a rule set. The rule set determines the
two key elements of a match: your game's team structure and size, and how to
group players together for the best possible match.

For example, a rule set might describe a match like this: Create a match with
two teams of four to eight players each, one team is the cowboy and the other
team the aliens. A team can have novice and experienced players, but the
average skill of the two teams must be within 10 points of each other. If no
match is made after 30 seconds, gradually relax the skill requirements.

```ts
new gamelift.MatchmakingRuleSet(this, 'RuleSet', {
matchmakingRuleSetName: 'my-test-ruleset',
content: gamelift.RuleSetBody.fromJsonFile(path.join(__dirname, 'my-ruleset/ruleset.json')),
});
```

### FlexMatch Monitoring

You can monitor GameLift FlexMatch activity for matchmaking configurations and
matchmaking rules using Amazon CloudWatch. These statistics are used to provide
a historical perspective on how your Gamelift FlexMatch solution is performing.

#### FlexMatch Metrics

GameLift FlexMatch sends metrics to CloudWatch so that you can collect and
analyze the activity of your matchmaking solution, including match acceptance
workflow, ticket consumtion.

You can then use CloudWatch alarms to alert you, for example, when matches has
been rejected (potential matches that were rejected by at least one player
since the last report) exceed a certain thresold which could means that you may
have an issue in your matchmaking rules.

CDK provides methods for accessing GameLift FlexMatch metrics with default configuration,
such as `metricRuleEvaluationsPassed`, or `metricRuleEvaluationsFailed` (see
[`IMatchmakingRuleSet`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-gamelift.IMatchmakingRuleSet.html)
for a full list). CDK also provides a generic `metric` method that can be used
to produce metric configurations for any metric provided by GameLift FlexMatch;
the configurations are pre-populated with the correct dimensions for the
matchmaking configuration.

```ts
declare const matchmakingRuleSet: gamelift.MatchmakingRuleSet;
// Alarm that triggers when the per-second average of not placed matches exceed 10%
const ruleEvaluationRatio = new cloudwatch.MathExpression({
expression: '1 - (ruleEvaluationsPassed / ruleEvaluationsFailed)',
usingMetrics: {
ruleEvaluationsPassed: matchmakingRuleSet.metricRuleEvaluationsPassed({ statistic: cloudwatch.Statistic.SUM }),
ruleEvaluationsFailed: matchmakingRuleSet.metric('ruleEvaluationsFailed'),
},
});
new cloudwatch.Alarm(this, 'Alarm', {
metric: ruleEvaluationRatio,
threshold: 0.1,
evaluationPeriods: 3,
});
```

See: [Monitoring Using CloudWatch Metrics](https://docs.aws.amazon.com/gamelift/latest/developerguide/monitoring-cloudwatch.html)
in the *Amazon GameLift Developer Guide*.


## GameLift Hosting

### Uploading builds and scripts to GameLift
Expand Down Expand Up @@ -344,7 +411,7 @@ in the *Amazon GameLift Developer Guide*.
GameLift is integrated with CloudWatch, so you can monitor the performance of
your game servers via logs and metrics.

#### Metrics
#### Fleet Metrics

GameLift Fleet sends metrics to CloudWatch so that you can collect and analyze
the activity of your Fleet, including game and player sessions and server
Expand Down Expand Up @@ -517,7 +584,7 @@ new gamelift.GameServerGroup(this, 'GameServerGroup', {
});
```

### Monitoring
### FleetIQ Monitoring

GameLift FleetIQ sends metrics to CloudWatch so that you can collect and
analyze the activity of your Game server fleet, including the number of
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-gamelift/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export * from './game-server-group';
export * from './ingress-rule';
export * from './fleet-base';
export * from './build-fleet';
export * from './matchmaking-ruleset';
export * from './matchmaking-ruleset-body';

// AWS::GameLift CloudFormation Resources:
export * from './gamelift.generated';
113 changes: 113 additions & 0 deletions packages/@aws-cdk/aws-gamelift/lib/matchmaking-ruleset-body.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import * as fs from 'fs';
import { Construct } from 'constructs';

/**
* The rule set determines the two key elements of a match: your game's team structure and size, and how to group players together for the best possible match.
*
* For example, a rule set might describe a match like this:
* - Create a match with two teams of five players each, one team is the defenders and the other team the invaders.
* - A team can have novice and experienced players, but the average skill of the two teams must be within 10 points of each other.
* - If no match is made after 30 seconds, gradually relax the skill requirements.
*/
export abstract class RuleSetBody {

/**
* Matchmaking ruleSet body from a file
* @returns `JsonFileRuleSetBody` with inline code.
* @param path The path to the ruleSet body file
*/
public static fromJsonFile(path: string): RuleSetBody {
return new JsonFileRuleSetBody(path);
}

/**
* Inline body for Matchmaking ruleSet
* @returns `InlineRuleSetBody` with inline code.
* @param body The actual ruleSet body (maximum 65535 characters)
*/
public static fromInline(body: string): RuleSetBody {
return new InlineRuleSetBody(body);
}

/**
* Called when the matchmaking ruleSet is initialized to allow this object to bind
* to the stack and add resources.
*
* @param scope The binding scope.
*/
public abstract bind(scope: Construct): RuleSetBodyConfig;
}

/**
* Result of binding `RuleSetBody` into a `MatchmakingRuleSet`.
*/
export interface RuleSetBodyConfig {
/**
* Inline ruleSet body.
*/
readonly ruleSetBody: string;
}

/**
* Matchmaking ruleSet body from an inline string.
*/
export class InlineRuleSetBody extends RuleSetBody {

/**
* @param path The ruleSet body.
*/
constructor(private body: string) {
super();

if (body.length === 0) {
throw new Error('Matchmaking ruleSet body cannot be empty');
}

if (body.length > 65535) {
throw new Error(`Matchmaking ruleSet body cannot exceed 65535 characters, actual ${body.length}`);
}
}

public bind(_scope: Construct): RuleSetBodyConfig {
return {
ruleSetBody: this.body,
};
}
}

/**
* Matchmaking ruleSet body from aJSON File.
*/
export class JsonFileRuleSetBody extends RuleSetBody {
/**
* Json file body content
*/
private content: string;

/**
* @param path The path to the ruleSert body file.
*/
constructor(private path: string) {
super();
if (!fs.existsSync(path)) {
throw new Error(`Matchmaking ruleSet path does not exist, please verify it, actual ${this.path}`);
}

if (!fs.lstatSync(path).isFile()) {
throw new Error(`Matchmaking ruleSet path is not link to a single file, please verify your path, actual ${this.path}`);
}
const file = fs.readFileSync(path);

if (file.toString().length > 65535) {
throw new Error(`Matchmaking ruleSet body cannot exceed 65535 characters, actual ${file.toString().length}`);
}

this.content = file.toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also make sure that the string is a valid JSON? (Same for the inline case).

}

public bind(_scope: Construct): RuleSetBodyConfig {
return {
ruleSetBody: this.content,
};
}
}