Skip to content

Commit ad8a704

Browse files
authored
feat(gamelift): add MatchmakingRuleSet L2 Construct for GameLift (#23091)
Following aws/aws-cdk-rfcs#436 I have written the Gamelift MatchmakingRuleSet L2 resource which create an MatchmakingRuleSet resource. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent fee2fa2 commit ad8a704

16 files changed

+1109
-2
lines changed

packages/@aws-cdk/aws-gamelift/README.md

+69-2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,73 @@ deliver inexpensive, resilient game hosting for your players
5050
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
5151
configuration or game server fleet management system.
5252

53+
## GameLift FlexMatch
54+
55+
### Matchmaking RuleSet
56+
57+
Every FlexMatch matchmaker must have a rule set. The rule set determines the
58+
two key elements of a match: your game's team structure and size, and how to
59+
group players together for the best possible match.
60+
61+
For example, a rule set might describe a match like this: Create a match with
62+
two teams of four to eight players each, one team is the cowboy and the other
63+
team the aliens. A team can have novice and experienced players, but the
64+
average skill of the two teams must be within 10 points of each other. If no
65+
match is made after 30 seconds, gradually relax the skill requirements.
66+
67+
```ts
68+
new gamelift.MatchmakingRuleSet(this, 'RuleSet', {
69+
matchmakingRuleSetName: 'my-test-ruleset',
70+
content: gamelift.RuleSetContent.fromJsonFile(path.join(__dirname, 'my-ruleset/ruleset.json')),
71+
});
72+
```
73+
74+
### FlexMatch Monitoring
75+
76+
You can monitor GameLift FlexMatch activity for matchmaking configurations and
77+
matchmaking rules using Amazon CloudWatch. These statistics are used to provide
78+
a historical perspective on how your Gamelift FlexMatch solution is performing.
79+
80+
#### FlexMatch Metrics
81+
82+
GameLift FlexMatch sends metrics to CloudWatch so that you can collect and
83+
analyze the activity of your matchmaking solution, including match acceptance
84+
workflow, ticket consumtion.
85+
86+
You can then use CloudWatch alarms to alert you, for example, when matches has
87+
been rejected (potential matches that were rejected by at least one player
88+
since the last report) exceed a certain thresold which could means that you may
89+
have an issue in your matchmaking rules.
90+
91+
CDK provides methods for accessing GameLift FlexMatch metrics with default configuration,
92+
such as `metricRuleEvaluationsPassed`, or `metricRuleEvaluationsFailed` (see
93+
[`IMatchmakingRuleSet`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-gamelift.IMatchmakingRuleSet.html)
94+
for a full list). CDK also provides a generic `metric` method that can be used
95+
to produce metric configurations for any metric provided by GameLift FlexMatch;
96+
the configurations are pre-populated with the correct dimensions for the
97+
matchmaking configuration.
98+
99+
```ts
100+
declare const matchmakingRuleSet: gamelift.MatchmakingRuleSet;
101+
// Alarm that triggers when the per-second average of not placed matches exceed 10%
102+
const ruleEvaluationRatio = new cloudwatch.MathExpression({
103+
expression: '1 - (ruleEvaluationsPassed / ruleEvaluationsFailed)',
104+
usingMetrics: {
105+
ruleEvaluationsPassed: matchmakingRuleSet.metricRuleEvaluationsPassed({ statistic: cloudwatch.Statistic.SUM }),
106+
ruleEvaluationsFailed: matchmakingRuleSet.metric('ruleEvaluationsFailed'),
107+
},
108+
});
109+
new cloudwatch.Alarm(this, 'Alarm', {
110+
metric: ruleEvaluationRatio,
111+
threshold: 0.1,
112+
evaluationPeriods: 3,
113+
});
114+
```
115+
116+
See: [Monitoring Using CloudWatch Metrics](https://docs.aws.amazon.com/gamelift/latest/developerguide/monitoring-cloudwatch.html)
117+
in the *Amazon GameLift Developer Guide*.
118+
119+
53120
## GameLift Hosting
54121

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

347-
#### Metrics
414+
#### Fleet Metrics
348415

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

520-
### Monitoring
587+
### FleetIQ Monitoring
521588

522589
GameLift FleetIQ sends metrics to CloudWatch so that you can collect and
523590
analyze the activity of your Game server fleet, including the number of

packages/@aws-cdk/aws-gamelift/lib/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export * from './game-server-group';
66
export * from './ingress-rule';
77
export * from './fleet-base';
88
export * from './build-fleet';
9+
export * from './matchmaking-ruleset';
10+
export * from './matchmaking-ruleset-body';
911

1012
// AWS::GameLift CloudFormation Resources:
1113
export * from './gamelift.generated';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import * as fs from 'fs';
2+
import { Construct } from 'constructs';
3+
4+
/**
5+
* Interface to represent Matchmaking RuleSet schema
6+
*/
7+
export interface IRuleSetBody {}
8+
9+
/**
10+
* Interface to represent output result of a RuleSetContent binding
11+
*/
12+
export interface RuleSetBodyConfig {
13+
/**
14+
* Inline ruleSet body.
15+
*/
16+
readonly ruleSetBody: string;
17+
}
18+
19+
/**
20+
* Interface to represent a Matchmaking RuleSet content
21+
*/
22+
export interface IRuleSetContent {
23+
24+
/**
25+
* RuleSet body content
26+
*
27+
* @attribute
28+
*/
29+
readonly content: IRuleSetBody;
30+
31+
/**
32+
* Called when the matchmaking ruleSet is initialized to allow this object to bind
33+
* to the stack and add resources.
34+
*
35+
* @param _scope The binding scope.
36+
*/
37+
bind(_scope: Construct): RuleSetBodyConfig;
38+
}
39+
40+
/**
41+
* Properties for a new matchmaking ruleSet content
42+
*/
43+
export interface RuleSetContentProps {
44+
45+
/**
46+
* RuleSet body content
47+
*
48+
* @default use a default empty RuleSet body
49+
*/
50+
readonly content?: IRuleSetBody;
51+
}
52+
53+
/**
54+
* 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.
55+
*
56+
* For example, a rule set might describe a match like this:
57+
* - Create a match with two teams of five players each, one team is the defenders and the other team the invaders.
58+
* - A team can have novice and experienced players, but the average skill of the two teams must be within 10 points of each other.
59+
* - If no match is made after 30 seconds, gradually relax the skill requirements.
60+
*/
61+
export class RuleSetContent implements IRuleSetContent {
62+
63+
/**
64+
* Matchmaking ruleSet body from a file
65+
* @returns `RuleSetContentBase` based on JSON file content.
66+
* @param path The path to the ruleSet body file
67+
*/
68+
public static fromJsonFile(path: string): IRuleSetContent {
69+
if (!fs.existsSync(path)) {
70+
throw new Error(`RuleSet path does not exist, please verify it, actual ${path}`);
71+
}
72+
73+
if (!fs.lstatSync(path).isFile()) {
74+
throw new Error(`RuleSet path is not link to a single file, please verify your path, actual ${path}`);
75+
}
76+
const file = fs.readFileSync(path);
77+
78+
return this.fromInline(file.toString());
79+
}
80+
81+
/**
82+
* Inline body for Matchmaking ruleSet
83+
* @returns `RuleSetContent` with inline code.
84+
* @param body The actual ruleSet body (maximum 65535 characters)
85+
*/
86+
public static fromInline(body: string): IRuleSetContent {
87+
if (body && body.length > 65535) {
88+
throw new Error(`RuleSet body cannot exceed 65535 characters, actual ${body.length}`);
89+
}
90+
try {
91+
return new RuleSetContent({
92+
content: JSON.parse(body),
93+
});
94+
} catch (err) {
95+
throw new Error('RuleSet body has an invalid Json format');
96+
}
97+
}
98+
99+
/**
100+
* RuleSet body content
101+
*/
102+
public readonly content: IRuleSetBody;
103+
104+
constructor(props: RuleSetContentProps) {
105+
this.content = props.content || {};
106+
}
107+
108+
/**
109+
* Called when the matchmaking ruleSet is initialized to allow this object to bind
110+
* to the stack and add resources.
111+
*
112+
* @param _scope The binding scope.
113+
*/
114+
public bind(_scope: Construct): RuleSetBodyConfig {
115+
return {
116+
ruleSetBody: JSON.stringify(this.content),
117+
};
118+
}
119+
}

0 commit comments

Comments
 (0)