Ping-pong is an interesting game. It is a game where two players hit a lightweight ball back and forth across a table using small rackets. The game takes place on a hard table divided by a net. When you look at the game as an observer you see some interesting things. The players act only when the ball is on their side of the table. Only then a player swings the racket and the ball starts to travel the other way. When you are working in IT, you start to recognize other things as well. There is an asynchronous process in the game. The players react on ball and act on it. Also, the ball has travels from left to right, and from right to left. Another interesting thing is that players only swing when the ball can be hit, but in between the players don’t do anything else. Lets try to model this process in a serverless way.
The ping pong model
To model the game Serverless, we can use AWS Lambda as act as players. For the ball, we can take a message. For the playing table we can take two message queue, one for the ‘left-to-right’ motion and one for the ‘right-to-left’ motion and AWS SNS is a perfect fit. For the rackets we can use the act of ‘publishing a message’. We also have to have a way to start the game, which will be by ‘serving the ball’. AWS CloudWatch events is perfect for this job. It will send a message to the lambda to ‘start serving’. Of course, you only serve one time, so we have to deal with that. To define the logic simple Python scripts suffice combined with the Python SDK for Python. The game will be deployed by means of Sceptre to AWS defining the desired state configuration of the serverless infrastructure using AWS CloudFormation templates. I think this can actually work!
The players
For the players we take two Lambdas that execute simple Python scripts. One Lambda is called ‘ping’ that starts the game, and the other one is called ‘pong’ that reacts by ‘hitting’ the ball back.
Ping Actor:
# remember the serve
started = False
def handler(event, ctx) -> None:
global started
if event.get('detail-type'): # cloudwatch event
if not started:
started = True
# hit the ball
publish(ctx.invoked_function_arn, 'ping-topic', 'ping')
else: # other event
# hit the ball
publish(ctx.invoked_function_arn, 'ping-topic', 'ping')
Pong Actor:
def handler(event, ctx):
# hit the ball
publish(ctx.invoked_function_arn, 'pong-topic', 'pong')
The playing table
We can model the table by using two Amazon SNS queues that will receive the messages from one actor and route the stream of messages to the other actor. The queues must have permissions to invoke the lambdas.
PingTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: ping-topic
Subscription:
- Endpoint: !GetAtt PongFunction.Arn
Protocol: lambda
PongTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: pong-topic
Subscription:
- Endpoint: !GetAtt PingFunction.Arn
Protocol: lambda
InvokePingPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt PingFunction.Arn
Action: lambda:invokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref PongTopic
InvokePongPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt PongFunction.Arn
Action: lambda:invokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref PingTopic
Start serving
To actually start the game, a player must start serving. The Ping actor already has the logic setup for that. A CloudWatch event will trigger the Ping actor to start the game. CloudWatch must have permission to invoke the lambda.
CloudWatchEventsRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: rate(1 minute)
State: ENABLED
Targets:
- Arn: !GetAtt PingFunction.Arn
Id: scheduled-event
InvokeLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt PingFunction.Arn
Action: lambda:invokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt CloudWatchEventsRule.Arn
Example
The example project shows how to configure a project to create a serverless ping-pong game. The example can be deployed with make deploy
and removed with make delete
.
Conclusion
A game like ping-pong is asynchronous by nature. Players play the game by reacting on events that are happening. Upon an event, players only have to do simple things like hitting the ball back. Serverless architectures are a perfect fit for asynchronous processes. By using message queues, asynchronous message passing and serverless compute, real life processes can be modeled in an event-driven way. Event Driven Architectures (EDA), like the ping-pong game we just created make efficient use of data centre resources and are the are a core architectural pattern and essential for serverless cloud computing. Next time we’ll look at how we can apply what we have learned from the ping-pong to and abstract some integration patterns from it!