PlayTech Assignment
Implement client and server in Java.
Server offers service for player wallet (balance). Wallet state (balance) should be managed in memory (3rd party solution may not be used). Balance is backed up in database (hsql or sqlite). When balance is not in memory, it is loaded from database and any changes are done in memory. Player record in database is created on demand.
There is a periodical background process to write changes from memory to database. Constraints on balance changes:
• Balance cannot be less than 0. • If transaction exists (is duplicate), then previous response is returned. Check may take into consideration only 1000 latest transactions. • If balance change is bigger than configured limit, then change is denied (explained further below). • If player is in blacklist, then change is denied (explained further below). Configuration (balance change limit and player blacklist) must be taken from external source. This can be file, database, external component etc. Client itself is a server that offers gameplay logic. Specific gameplay will not be implemented, client can just generate random balance updates. Specific communication protocol between client and server is not specified (custom protocol can be invented). Server must write proper log information, where at least IN/OUT per player must be grep’able.
client->server: username, transaction id, balance change
server->client: transaction id, error code, balance version, balance change, balance after change
Database structure PLAYER(USERNAME, BALANCE_VERSION, BALANCE)
• Describe shortly the implementation aspects. • If some features are not implemented, point out the reasons Building and Packaging: • The solution can be built using any commonly available build framework (e.g. Maven, Gradle, Ant). Providing project-local wrappers for running the build in-place are appreciated. • As a part of the build, the solution should be packaged into Docker containers. Do not publish the solution to a public Docker repository; providing Dockerfiles and docker-compose or instructions on how to build and run the containerized solution should be enoug
Code can run via
./mvnw spring-boot:run
client ui is available at http://localhost:8080/
Sample Request For Credit
{
"userName": "nithin2",
"transactionId": "456",
"balance": "123"
}
Sample Request For Debit
{
"userName": "nithin2",
"transactionId": "456",
"balance": "-123"
}
Sample Response
{
"transactionId": "456",
"balanceVersion": "1",
"errorCode": null,
"balanceChange": 0,
"balanceAfterChange": 123
}
List Of Error codes
- BALANCE_CANNOT_BE_LESS_THAN_ZERO,
- BALANCE_CAANOT_BE_MORE_THAN_CONFIGURED_LIMIT,
- USER_IS_CURRENTLY_BLOCKED,
- DUPLICATE_TRANSACTION
Cors are disabled and allow only for same origin
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
@Controller
public class WalletController {
@Autowired
WalletUpdateService service;
@MessageMapping("/update")
@SendTo("/topic/public")
public WalletUpdateResponse register(@Payload WalletUpdateInput input, SimpMessageHeaderAccessor headerAccessor) {
MDC.put("username",input.getUserName());
WalletUpdateResponse updateResponse= service.updateWallet(input);
MDC.clear();
return updateResponse;
}
}
Format
${CONSOLE_LOG_PATTERN:-%clr(SERVER){green} %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%X{username:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}
Sample
SERVER 2022-02-15 15:09:14.956 INFO 67464 nithin --- [nboundChannel-9] c.p.n.p.s.service.WalletUpdateService : OutGoing Response WalletUpdateResponse(transactionId=null, balanceVersion=2, errorCode=null, balanceChange=11, balanceAfterChange=22)
Can grep logs by username in above case its nithin
Default Running on port 8080
Name | Default Value | Describtion |
---|---|---|
spring.datasource.url | jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1 | hostname/service where hsql server is running |
spring.datasource.username | sa | username |
spring.datasource.password | password | |
server.port | 8080 | default port |
limit.maxlimit | 10000 | maximum configurable limit |
scheduler.interval | 100000 | Scheduler interval for periodic backup |
Can build a docker image by
docker build -t nithinprasad549/playtech .
Alternative can build docker image by
./mvnw spring-boot:build-image
Docker compose file
version: '3'
services:
playtech:
image: nithinprasad549/playtech
environment:
- spring.datasource.url=jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1
- spring.datasource.username=sa
- limit.maxlimit=10000
- scheduler.interval=100000