This repository has been archived by the owner on Nov 11, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #307 Added Kubernetes docs page Updated vault docs Updated events & data streams docs Added fsm docs Added local setup & startup guide Added grafana to cluster architecture image Updated events chart to correctly reflect historization events Added service catalog to main readme Updated readme for each service
- Loading branch information
Showing
41 changed files
with
960 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,34 @@ | ||
# Docker Registry | ||
REGISTRY=ghcr.io/fortify-labs/fortify/ | ||
|
||
# Vault Auth Token; Will be reworked into a Kubernetes service account based auth method | ||
VAULT_TOKEN= | ||
|
||
# Production Environment? prod / dev / staging | ||
ENVIRONMENT= | ||
# Basic auth for dev & monitoring services (htpasswd string) | ||
CLUSTER_BASIC_AUTH= | ||
|
||
# Production domain | ||
DOMAIN= | ||
# Google analytics tracking id | ||
GA_TRACKING_ID= | ||
|
||
# Sentry.io DSNs for each service | ||
SENTRY_DSN= | ||
TWITCH_BOT_SENTRY_DSN= | ||
GSI_RECEIVER_SENTRY_DSN= | ||
FSM_SENTRY_DSN= | ||
HISTORIZATION_SENTRY_DSN= | ||
JOBS_SENTRY_DSN= | ||
BACKEND_SENTRY_DSN= | ||
|
||
# Grafana SSO | ||
GRAFANA_GITHUB_CLIENT_ID= | ||
GRAFANA_GITHUB_CLIENT_SECRET= | ||
|
||
# S3 for backups | ||
S3_ENDPOINT= | ||
S3_REGION= | ||
S3_ACCESS_KEY_ID= | ||
S3_SECRET_ACCESS_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Events | ||
|
||
Fortify is designed with an event driven architecture in mind. | ||
|
||
This means that events can be generated from any service at any time and can be processed by any service subscribing to them at any time with variable delays and lags. | ||
|
||
Kafka is being utilized as message queue, serving as a common interface for all services & languages, enabling the decoupling of services and offering flexibility for future implementations. | ||
|
||
## Event Types | ||
|
||
In total there are 3 different type of events: | ||
|
||
- [Game](#Game-Events) | ||
- [Generic](#Generic-Events) | ||
- [System](#System-Events) | ||
|
||
Each event type is written to its corresponding Kafka topic, which in turn has custom retention rules. | ||
|
||
All events have a `type` and a `timestamp`, with `timestamp` allowing delayed event processing in case of failures, unforeseen burst loads or batch processing. | ||
|
||
The following is a rough chart of data streams inside of Fortify: | ||
|
||
![data streams chart](assets/events.png) | ||
|
||
## Game Events | ||
|
||
- `MATCH_STARTED`: Event created when a new match is detected (FSM generated event) | ||
- `FINAL_PLACE`: Event created when a player got eliminated with a final placing (FSM generated event) | ||
- `MATCH_ENDED`: Event created when a match has concluded with a first place winner (FSM generated event) | ||
- `RANK_TIER_UPDATE`: Event created when a match starts, includes a players current rank tier (FSM generated event) | ||
- `SMURF_DETECTED`: Event created when a smurf account has been detected (FSM generated event) | ||
- `UNIT_STATS`: Event created after each combat, tracking unit win/loss in conjunction with active alliances and equipped item (FSM generated event) | ||
- `ITEM_STATS`: Event created after each combat, tracking item win/loss in conjunction with active alliances (FSM generated event) | ||
- `ALLIANCE_STATS`: Event created after each combat, tracking alliance win/loss in conjunction with active alliances (FSM generated event) | ||
- `COMBINED_STATS`: Event combining all 3 stats event for easier batch processing for time series / wide column databases (FSM generated event) | ||
|
||
## Generic Events | ||
|
||
Currently unused | ||
|
||
## System Events | ||
|
||
- `FSM_RESET_REQUEST`: RPC event used to reset the finite state machines user state. (Twitch bot / manually generated event) | ||
- `TWITCH_LINKED`: Event created when a Twitch account has been linked with Fortify (backend generated event) | ||
- `TWITCH_UNLINKED`: Event created when a Twitch account has been unlinked with Fortify (backend generated event) | ||
- `TWITCH_MESSAGE_BROADCAST`: Event used to broadcast a message to all twitch channels the bot is currently joined in (manually generated event) | ||
- `IMPORT_COMPLETED`: Event announcing a successful import of the Underlords leaderboard (import jobs generated event) | ||
- `HISTORIZATION_COMPLETED`: Event announcing successful storing individual ranks of the imported leaderboard (historization generated event) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Finite State Machine | ||
|
||
Fortify's finite state machine is the heart of the entire operation, successfully processing millions of GSI messages per month. | ||
|
||
Initially, the finite state machine was hastily written together and started to show it's shortcomings. These shortcomings included slow processing under load and incorrectly detected game modes, rendering any future use for stats collection impossible. | ||
|
||
This lead to a complete redesign & rewrite from scratch, with many new features and fixes baked into it. | ||
|
||
A rough, high-level view of the finite state machine can be seen bellow: | ||
|
||
![fsm chart](assets/fsm.png) | ||
|
||
## Features | ||
|
||
- Detect Game Modes | ||
- Correct unit pool sizes & odds for each game mode | ||
- Game state tracking | ||
- Rough round number estimations | ||
- Rank progression tracking | ||
- Player lobby processing | ||
- Consolidated unit pool | ||
- Individual board states | ||
- Processing of private player states | ||
- Smurf detection | ||
- Unit / Item / Alliance (or to be technically correct: Synergy) performance tracking | ||
|
||
## Consolidated match states | ||
|
||
With multiple player potentially being in the same match, it's not only wasteful to keep separate match states for each player, but information might also get lost, if the transmitted of one player's GSI information has gotten lost. This might lead to incorrect calculations and stats tracking. | ||
|
||
In order to prevent this from happening, all players from one match are all sourced together into one combined match state. | ||
|
||
This is introducing a new data inconsistency scenario. As in one player's GSI data is sent with a major lag compared to other players, thus overriding newer data with old data. | ||
|
||
In order to avoid this scenarios of potential race conditions and data inconsistencies, the finite state machine is only performing updates on each public and private player state individually, if the `sequence_number` is higher than the previously stored `sequence_number`. | ||
|
||
## Shortcomings | ||
|
||
Two minor shortcomings of the above finite state machine can be broken down into missing information and information having to be guessed / estimated. | ||
|
||
### Unknown match ID | ||
|
||
GSI is not forwarding any information about the actual match itself (unlike it's counterpart in Dota and CS GO). | ||
|
||
In order to still be able to track matches, the finite state machine is creating it's own match ID based of player account IDs and their slots inside of the lobby, which is then piped into a hash function. | ||
|
||
In case of "collisions" (generated match ID has already been used and the original match identified by said ID already has player slots with a final_place set), the above match id generation will have a nonce appended, which will gradually increase until a match ID has been generated, that has not been used before. | ||
|
||
### Unknown round number | ||
|
||
Like with the unknown match ID, round numbers are also not present in GSI data. | ||
|
||
This unknown variable can be guesstimated by taking the Underlords levels into consideration, as Underlord levels are tied to round numbers & game modes. | ||
|
||
## Happy Little Accidents | ||
|
||
When designing the new version of the finite state machine, I have not considered handling the duos game mode. | ||
|
||
Thus the finite state machine was originally designed to primarily work with 8 player lobbies, yet this number has not been capped anywhere in the final implementation. | ||
|
||
For some reason, the finite state machine managed to correctly detect duos lobby and wait for all 16 players public player states. | ||
|
||
So technically a desired feature, that was not planed at all and manifested itself as a bug. So quite literally a bug turning into a feature. (Probably one of my best & proudest bugs.) |
Oops, something went wrong.