Skip to content

Commit ca9ffdd

Browse files
authored
Expose game service via messaging (#297)
Expose OpenGame, JoinGame, MakeMove, and GetGamesByPlayer. Extend from DomainException to enable automatic error handling in message consumers. Rewrite the RPC queues to use a single routing key and distinguish between long-running and immediate responses #122.
1 parent 4020a3d commit ca9ffdd

27 files changed

+341
-27
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,10 @@ Check out the purpose and architectural decisions of each context in the section
250250
**Purpose**: [Connect Four](/src/ConnectFour) handles games from players opening a game,
251251
through others joining and making moves, till they are finished (win, lose, or draw).
252252

253-
**Communication**: Its use cases are directly invoked by the Web Interface to reduce network hops and abstractions.
253+
**Communication**: Its use cases are exposed via
254+
[messaging](https://www.enterpriseintegrationpatterns.com/patterns/messaging/Messaging.html), utilizing
255+
[Request-Reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html),
256+
with some directly invoked by the Web Interface to reduce network hops and abstractions.
254257
To notify other contexts about what has happened, [Domain Events](https://martinfowler.com/eaaDev/DomainEvent.html)
255258
are stored in a [Transactional Outbox](https://en.wikipedia.org/wiki/Inbox_and_outbox_pattern) and
256259
later published in JSON format using

assets/js/ConnectFour/Timer.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ customElements.define('connect-four-timer', class extends HTMLElement {
1414
this._panicLevelThreeBelowMs = parseInt(this.getAttribute('panic-three-below-ms') || 3000);
1515
this._currentTickSound = null;
1616

17-
window.requestAnimationFrame(this._render);
17+
this._animationFrameId = window.requestAnimationFrame(this._render);
1818

1919
sse.subscribe(`connect-four-${this.getAttribute('game-id')}`, {
2020
'ConnectFour.PlayerJoined': this._onPlayerJoined,
@@ -29,6 +29,7 @@ customElements.define('connect-four-timer', class extends HTMLElement {
2929

3030
disconnectedCallback() {
3131
this._sseAbortController.abort();
32+
cancelAnimationFrame(this._animationFrameId);
3233
}
3334

3435
_render = () => {
@@ -57,7 +58,7 @@ customElements.define('connect-four-timer', class extends HTMLElement {
5758
scriptune.play(`#BPM 300\nC5:s ${isPanicLevelThree ? '-:s C5:s' : ''}`)
5859
}
5960

60-
window.requestAnimationFrame(this._render);
61+
this._animationFrameId = window.requestAnimationFrame(this._render);
6162
}
6263

6364
_onPlayerJoined = e => {

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"doctrine/doctrine-migrations-bundle": "^3.3",
3737
"doctrine/migrations": "^3.7",
3838
"doctrine/orm": "^3.0",
39-
"gaming-platform/api": "^1.5",
39+
"gaming-platform/api": "^1.6",
4040
"jms/serializer": "^3.17",
4141
"marein/php-nchan-client": "^3.1",
4242
"marein/symfony-lock-doctrine-migrations-bundle": "^1.0",

composer.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/connect-four/services/consumer.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
11
services:
2+
connect-four.transient-rpc-message-handler.topology:
3+
class: Gaming\Common\MessageBroker\Integration\AmqpLib\Topology\QueueTopology
4+
arguments: ['ConnectFour.TransientRpc', 'gaming', ['ConnectFour.TransientRpc'], {'x-expires': 7000}]]
5+
tags: [{ name: 'gaming.message-broker.topology' }]
6+
7+
connect-four.transient-rpc-message-handler.consumer:
8+
class: Gaming\Common\MessageBroker\Integration\AmqpLib\AmqpConsumer
9+
factory: ['@gaming.message-broker.amqp-consumer-factory', 'create']
10+
arguments:
11+
- !service
12+
class: Gaming\ConnectFour\Port\Adapter\Messaging\RpcMessageHandler
13+
arguments: ['@connect-four.command-bus', '@connect-four.query-bus']
14+
- !service
15+
class: Gaming\Common\MessageBroker\Integration\AmqpLib\QueueConsumer\ConsumeQueues
16+
arguments: ['@connect-four.transient-rpc-message-handler.topology']
17+
tags: [{ name: 'gaming.consumer', key: 'connect-four.transient-rpc' }]
18+
219
connect-four.referee-message-handler.topology:
320
class: Gaming\Common\MessageBroker\Integration\AmqpLib\Topology\QueueTopology
421
arguments: ['ConnectFour.Referee', 'gaming', ['ConnectFour.PlayerJoined']]
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
services:
2-
identity.bot-requests-message-handler.topology:
2+
identity.transient-rpc-message-handler.topology:
33
class: Gaming\Common\MessageBroker\Integration\AmqpLib\Topology\QueueTopology
4-
arguments: ['Identity.BotRequests', 'gaming', [
5-
!php/const GamingPlatform\Api\Identity\V1\IdentityV1::RegisterBotType,
6-
!php/const GamingPlatform\Api\Identity\V1\IdentityV1::GetBotByUsernameType
7-
]]
4+
arguments: ['Identity.TransientRpc', 'gaming', ['Identity.TransientRpc'], {'x-expires': 7000}]]
85
tags: [{ name: 'gaming.message-broker.topology' }]
96

10-
identity.bot-requests-message-handler.consumer:
7+
identity.transient-rpc-message-handler.consumer:
118
class: Gaming\Common\MessageBroker\Integration\AmqpLib\AmqpConsumer
129
factory: ['@gaming.message-broker.amqp-consumer-factory', 'create']
1310
arguments:
1411
- !service
15-
class: Gaming\Identity\Port\Adapter\Messaging\BotRequestsMessageHandler
12+
class: Gaming\Identity\Port\Adapter\Messaging\RpcMessageHandler
1613
arguments: ['@identity.command-bus', '@identity.query-bus']
1714
- !service
1815
class: Gaming\Common\MessageBroker\Integration\AmqpLib\QueueConsumer\ConsumeQueues
19-
arguments: ['@identity.bot-requests-message-handler.topology']
20-
tags: [{ name: 'gaming.consumer', key: 'identity.command' }]
16+
arguments: ['@identity.transient-rpc-message-handler.topology']
17+
tags: [{ name: 'gaming.consumer', key: 'identity.transient-rpc' }]

deploy/load-test/stack/connect-four/app.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ services:
4747
- "node.labels.long-running==1"
4848
labels:
4949
- "prometheus-job=connect-four-publish-to-browser"
50+
connect-four-game-requests:
51+
image: marein/php-gaming-website:php-fpm
52+
command: bin/console gaming:consume-messages connect-four.game-requests -r 3
53+
env_file: ../app.env
54+
volumes:
55+
- proxysql.sock:/var/run/proxysql
56+
deploy:
57+
placement:
58+
constraints:
59+
- "node.labels.long-running==1"
60+
labels:
61+
- "prometheus-job=connect-four-game-requests"
5062

5163
volumes:
5264
proxysql.sock:

deploy/load-test/stack/identity/app.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
version: '3.4'
22

33
services:
4+
identity-bot-requests:
5+
image: marein/php-gaming-website:php-fpm
6+
command: bin/console gaming:consume-messages identity.bot-requests -r 3
7+
env_file: ../app.env
8+
volumes:
9+
- proxysql.sock:/var/run/proxysql
10+
deploy:
11+
placement:
12+
constraints:
13+
- "node.labels.long-running==1"
14+
labels:
15+
- "prometheus-job=identity-bot-requests"
416
identity-follow-event-store:
517
image: marein/php-gaming-website:php-fpm
618
command: bin/console identity:follow-event-store pointer all

src/ConnectFour/Domain/Game/Board/Size.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ final class Size
1818
public function __construct(int $width, int $height)
1919
{
2020
if ($width < 2 || $height < 2) {
21-
throw new InvalidSizeException('Width and height must be greater then 1.');
21+
throw InvalidSizeException::tooSmall($width, $height);
2222
}
2323

2424
if (($width * $height) % 2 !== 0) {
25-
throw new InvalidSizeException('Product of width and height must be an even number.');
25+
throw InvalidSizeException::productNotEven($width, $height);
2626
}
2727

2828
$this->height = $height;

src/ConnectFour/Domain/Game/Exception/ColumnAlreadyFilledException.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
namespace Gaming\ConnectFour\Domain\Game\Exception;
66

7+
use Gaming\Common\Domain\Exception\Violation;
8+
use Gaming\Common\Domain\Exception\Violations;
9+
710
final class ColumnAlreadyFilledException extends GameException
811
{
12+
public function __construct()
13+
{
14+
parent::__construct(new Violations(new Violation('column_already_filled')));
15+
}
916
}

0 commit comments

Comments
 (0)