A very simple accounts application using Vert.x and Crabzilla

Overview

Accounts2

crabzilla.v0.3.5 orange

This is an example of an application using Vert.x and Crabzilla

Status

Work in progress

Requirements

  • Java 11

  • Maven

  • Docker compose

Running

1 - Start Postgres:

docker-compose up

2 - Run the tests:

mvn clean verify

3 - Run the application:

mvn clean compile exec:java

Test scenarios

Core model unit tests

class AccountsSpecsTest : AnnotationSpec() {

  val id = UUID.randomUUID()
  val config = CommandControllerConfig("Account", accountEventHandler, { AccountCommandHandler() })

  @Test
  fun `opening an account with bonus credit`() {
    TestSpecification(config)
      .whenCommand(OpenAccount(id, 100.00))
      .then { it.state() shouldBe Account(id, 100.00) }
      .then { it.events() shouldBe listOf(AccountOpened(id, 100.00)) }
  }

  @Test
  fun `depositing money`() {
    TestSpecification(config)
      .givenEvents(AccountOpened(id, 100.00))
      .whenCommand(DepositMoney(200.00))
      .then { it.state() shouldBe Account(id, 300.00) }
      .then {
        it.events() shouldBe listOf(
          AccountOpened(id, 100.00),
          MoneyDeposited(200.00, 300.00)
        )
      }
  }

  // etc...
}

Note: your core unit tests does not depends on vertx-core, only on crabzilla-core.

Integration tests

  • TODO

Manual tests

Pessimistic locking concurrent test

  • First, open an account 25a4b17c-3512-11ec-8d3d-0242ac130003 with $100.00

docker run --network host -i loadimpact/k6 run - <./k6/open-account-with-100.js

Then the snapshot state will be:

{"id": "25a4b17c-3512-11ec-8d3d-0242ac130003", "type": "Account", "balance":  100.00}

And the generated event:

{"id": "25a4b17c-3512-11ec-8d3d-0242ac130003", "type": "AccountOpened", "bonusCredit": 100.0}
  • Then try to withdraw $10.00 with 10 virtual users for 10 seconds:

docker run --network host -i loadimpact/k6 run --vus 10 --duration 10s - <./k6/withdraw-10-from-account.js

Then the account 25a4b17c-3512-11ec-8d3d-0242ac130003 state will be:

{"id": "25a4b17c-3512-11ec-8d3d-0242ac130003", "type": "Account"}

Now balance is omitted because its value is now zero. And the events for the stream are:

{
  "events": [
    {
      "event_payload": "{\"id\": \"25a4b17c-3512-11ec-8d3d-0242ac130003\", \"type\": \"AccountOpened\", \"bonusCredit\": 100.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 90.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 80.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 70.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 60.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 50.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 40.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 30.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 20.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 10.0}"
    },
    {
      "event_payload": "{\"type\": \"MoneyWithdrawn\", \"amount\": 10.0, \"finalBalance\": 0.0}"
    }
  ]
}

So, although the API received a lot of concurrent requests, only 10 withdraw command requests were successful. ACID is good :)

Stress test

  • Opening many accounts with 1000 virtual users for 60 seconds:

docker run --network host -i loadimpact/k6 run --vus 1000 --duration 60s - <./k6/open-many-accounts.js

And you will see something like:

         /\      |‾‾| /‾‾/   /‾‾/
     /\  /  \     |  |/  /   /  /
    /  \/    \    |     (   /   ‾‾\
   /          \   |  |\  \ |  (‾)  |
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: -
     output: -

  scenarios: (100.00%) 1 scenario, 1000 max VUs, 1m30s max duration (incl. graceful stop):
           * default: 1000 looping VUs for 1m0s (gracefulStop: 30s)
     data_received..................: 39 MB  648 kB/s
     data_sent......................: 25 MB  414 kB/s
     http_req_blocked...............: avg=890.28µs min=847ns    med=2.26µs   max=281.92ms p(90)=5.48µs   p(95)=7.37µs
     http_req_connecting............: avg=876.3µs  min=0s       med=0s       max=281.89ms p(90)=0s       p(95)=0s
     http_req_duration..............: avg=473.78ms min=81.67ms  med=544.84ms max=1.11s    p(90)=812.89ms p(95)=915.29ms
       { expected_response:true }...: avg=473.78ms min=81.67ms  med=544.84ms max=1.11s    p(90)=812.89ms p(95)=915.29ms
     http_req_failed................: 0.00%  ✓ 0           ✗ 126587
     http_req_receiving.............: avg=41.09µs  min=9.78µs   med=30.58µs  max=15.49ms  p(90)=70.1µs   p(95)=92.86µs
     http_req_sending...............: avg=129.8µs  min=6.07µs   med=15.78µs  max=52.38ms  p(90)=35.53µs  p(95)=49.09µs
     http_req_tls_handshaking.......: avg=0s       min=0s       med=0s       max=0s       p(90)=0s       p(95)=0s
     http_req_waiting...............: avg=473.61ms min=79.73ms  med=544.79ms max=1.11s    p(90)=812.8ms  p(95)=915.17ms
     http_reqs......................: 126587 2091.369327/s
     iteration_duration.............: avg=474.94ms min=129.55ms med=545.22ms max=1.12s    p(90)=813.16ms p(95)=915.65ms
     iterations.....................: 126587 2091.369327/s
     vus............................: 1000   min=1000      max=1000
     vus_max........................: 1000   min=1000      max=1000

Conclusion

  • You have a clean and testable CQRS domain model.

  • Idiomatic Kotlin: type safeness: pattern matching, honor your constructors

  • Immutability: state transitions occurs after computing results of pure functions (State, Event) → State

  • JSON serialization using Kotlin serialization

To handle your command in a non-blocking way, Crabzilla will :

  • Validate your command using your implementation of:

fun interface CommandValidator<C : Command> {
  fun validate(command: C): List<String>
}
  • Lock the target state instance (using Postgres Advisory Locks).

  • Retrieve the target snapshot (state and version).

  • Submit your command and snapshot.state using your implementation of:

abstract class CommandHandler<S : State, C : Command, E : Event>(applier: EventHandler<S, E>) :
  CommandHandlerApi<S, C, E>(applier) {
  abstract fun handleCommand(command: C, state: S?): CommandSession<S, E>
}
  • Persistence (within a db transaction)

    • Persist your command as JSON to commands table.

    • Persist the resulting events + metadata as JSON to events table.

    • Optionally persist the resulting snapshot (state and version) as JSON to snapshots table.

  • Return a SessionData to the caller:

data class CommandSessionData(
  val originalState: State?,
  val events: List<Event>,
  val newState: State
)

And about 2K TPS running all the stack within on my local machine. It’s pretty fair for many use cases.

From here, you can use any mechanism (manual, CDC, etc) to publish these events to wherever you need.

Next steps (TODO)

  • Projecting events

You might also like...
A simple android application for IQ tests, contains 40 questions and issues.
A simple android application for IQ tests, contains 40 questions and issues.

IQ-Android A simple android application for IQ tests, contains 40 questions and issues. Compatible with API Level 14 and higher Support only arabic la

This is a sample app to demonstrate the power of using EventSourced models and the ease with which these can be modelled using Kotlin.
This is a sample app to demonstrate the power of using EventSourced models and the ease with which these can be modelled using Kotlin.

Lego 4 Rent This is a sample app to demonstrate the power of using EventSourced models and the ease with which these can be modelled using Kotlin. To

Grocery - A simple CRUD Project using Spring Boot, Kotlin and MongoDB

Grocery - A simple CRUD Project using Spring Boot, Kotlin and MongoDB

Simple Login using firebase and compose views
Simple Login using firebase and compose views

SimpleLogin Project name: SimpleLogin Android Develop in android over MVVM, Kotlin, Compose. Package Structure com.anelcc.SimpleLogin # Root Pack

Android application compatible with ZX2C4's Pass command line application
Android application compatible with ZX2C4's Pass command line application

Password Store Download Documentation We're in the process of rewriting our documentation from scratch, and the work-in-progress state can be seen her

Push notification application using One Signal + Spring Boot + Kotlin

Spring Boot push notification system using One Signal This project was created to demonstrate a simple application built with Kotlin + Spring Boot inc

A basic template ecommerce application with payment integration made using Android Architechture componets
A basic template ecommerce application with payment integration made using Android Architechture componets

ShopIt ShopIt is a basic template ecommerce application with payment integration(RazorPay), made using Android Architechture componets and Material Co

An e-commerce mobile application built using Android Studio + Java + Firebase.
An e-commerce mobile application built using Android Studio + Java + Firebase.

E-Commerce An e-commerce mobile application built using Android Studio + Java + Firebase. Login for : [email protected] 123456 Screenshots of the app : L

Mock up social media android application created to interact with a backend Java server using GraphQL.

The Community Board Project Authorship: author: dnglokpor date: may 2022 Project Summary: The Community Board Project consists of a Java Spring Boot b

Owner
rodolfodpk
rodolfodpk
High performance and fully asynchronous pulsar client with Kotlin and Vert.x

pulsarkt High performance pulsar client with Kotlin and Vert.x Features Basic Producer/Consumer API Partitioned topics Batching Chunking Compression T

null 1 Nov 5, 2021
A very simple Android app which shows you random memes with the help of meme-api which you can share with your friends!

Meme Share A very simple Android app which shows you random memes with the help of meme-api which you can share with your friends! Tech stack 100% wri

Stɑrry Shivɑm 8 Aug 10, 2022
A stable and very powerful Kotlin bot.

Nabi 나비 Yeah idk what to put here anymore stfu azoo bloo Also chat commands are not being considered so no I don't recommend that you build the entire

myosyn 2 Oct 5, 2022
This is an example of a simple application with layered software base on clean-architecture as application architecture and mvvm as presentation architecture

This is an example of a simple application with layered software base on clean-architecture as application architecture and mvvm as presentation archi

null 3 Jul 2, 2021
Quiz Zone is a simple ✅ Quiz Android application 📱 using Firbase Firestore Database and Material Design.

Quiz Zone Quiz Zone is a simple ✅ Quiz Android application ?? using Firbase Firestore Database and Material Design. You can Install and test Quiz Zone

MOHIT GUPTA 6 Dec 24, 2022
A simple Android application to store daily notes in the internal database of the application

Simple Note App Note App is a simple Android application to store daily notes in the internal database of the application and can store an image or a

Heba Elsaid 5 Jun 3, 2022
A complete Kotlin application built to demonstrate the use of Modern development tools with best practices implementation using multi-module architecture developed using SOLID principles

This repository serves as template and demo for building android applications for scale. It is suited for large teams where individuals can work independently on feature wise and layer wise reducing the dependency on each other.

Devrath 11 Oct 21, 2022
Showify is a my first simple ✅ Android application 📱 using DI, where I learn how to use dagger-hilt, retrofit2, mvvm, livedata, Requestly Interceptor

Showify is a my first simple ✅ Android application ?? using DI, where I learn how to use dagger-hilt, retrofit2, mvvm, livedata, Requestly Interceptor and so much more...

MOHIT GUPTA 1 Jun 21, 2022
Login-and-Signup - Simple Login-and-Signup with authentication using Firebase API

Simple Login-and-Signup with authentication using Firebase API. Log in Sign Up

Indresh Goswami 0 Mar 25, 2022
LinkHub is a simple and effective link management application that can help you to easily manage your app with no ads!

LinkHub LinkHub is a simple and effective link management application that can help you to easily manage your own links with no ads! Download Screensh

Amr Hesham 71 Dec 17, 2022