- Docker CLI
- Docker Desktop, Colima or some mechanism to run containers on your host
- JDK 17 (if you use Mise or ASDF you can
mise install
orasdf install
to install one using the .tool-versions)
To get started working on Recce:
- Build Lint, Test and compile
./gradlew build ./batect build # Alternative within container. Will be slower, but perhaps cleaner.
- Run Recce within a container with an example scenario against a source/target DB
./batect -f examples/batect-petshop-mariadb.yml run
- Explore Recce's API (after running it) via http://localhost:8080/rapidoc/
- Build a Docker image locally and run it with an example scenario a
./gradlew jibDockerBuild && ./batect -f examples/batect-petshop-mariadb.yml run-docker-local
- Run A PostgreSQL DB on its own to use with Recce locally
./batect run-db ./gradlew run # or run/debug `RecceServer.kt` from your IDE
- Run Only Recce's dependencies with an example scenario, so you can run/debug/profile Recce itself outside Docker
./batect -f examples/batect-petshop-mariadb.yml run-deps ./gradlew run # or run/debug `RecceServer.kt` from your IDE
If using IntelliJ IDEA, you should be able to create the project from the clone location and IntelliJ will detect it as a Gradle project and import it directly. There are a couple of minor tweaks to make.
- Project Settings > Project > Ensure SDK and language level is set to Java 17
- Gradle > Gradle Settings > Set
Run Tests Using
toIntelliJ IDEA
.- This will typically give you much faster feedback than waiting for the Gradle runner. Unfortunately at time of writing you cannot build using IntelliJ IDEA natively, because kapt annotation processing for Kotlin is not supported outside of Gradle/Maven builds.
Recce is a Micronaut JVM application written in Kotlin using a broadly reactive asynchronous style using Project Reactor.
- Micronaut is used to externalise configuration for both Recce itself and configuration of new data sources
- Micronaut User Guide | API Reference | Configuration Reference | Guides
- Recce has its own Postgresql database which is used to
- store details of reconciliation runs
- store results for datasets, which may include row-by-row hashes
- Connectivity to Recce's own database uses R2DBC rather than JDBC to allow end-to-end non-blocking access
- As a relatively simply DB application, it uses Micronaut Data R2DBC as an ORM library (rather than a full JPA implementation such as Hibernate). Micronaut Data is not as fully featured as something such as Hibernate.
- DB migrations are being handled with Flyway
- Recce uses raw Micronaut Data R2DBC SQL to execute configured queries (example) defined against external databases
- Gradle (Kotlin-style) is used for build automation
- Code is linted using Spotless Gradle, with ktlint for Kotlin.
- Tip: Spotless/ktlint can auto-fix a lot of nitpicks with
./gradlew spotlessApply
- Tip: Spotless/ktlint can auto-fix a lot of nitpicks with
- Detekt & FindSecBugs (with SpotBugs) are used for static analysis from a coding practices and security perspective.
- Batect is available to automate dev+testing tasks within containers, including running Recce locally
- GitHub Actions are being used to automate build+test
- Tests are written using JUnit Jupiter with AssertJ and Mockito for mocking support
- At time of writing, Recce's own DB tests are tested against H2 Database rather than Postgres, for improved feedback, however this imposes some limitations and may need to be re-evaluated later
- Testcontainers are used for starting external DBs of various types to test against
- Rest-assured is used for API tests
These tend to evolve over time and should be re-evaluated as needed, however
- Tests named
*IntegrationTest
involve integration with a normally separate dependent component, such as a database. - Tests named
*ApiTest
test an API via Micronaut HTTP using real HTTP calls, thus verifying the contract - Other tests are mainly pure unit tests; although might do "fast" things such as use Micronaut to load configuration
Due to the config-driven nature of the tool, there are a number of tests which load Micronaut configuration via @MicronautTest
or ApplicationContext.run(props)
. Since certain config files are automatically loaded, to keep these as fast as possible the default configurations in application.yml
and application-test.yml
should be as light as possible and avoid doing slow things, triggering automated processes etc.
Some tests run within containers via Testcontainers. You might have issues if you are using Colima rather than Docker.
Try setting the below per this issue.
export DOCKER_HOST="unix:///${HOME}/.colima/docker.sock"
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
Running ./batect
run fails and returns an error with error code 137
. The stack trace also indicates a HeapDumpOnOutOfMemoryError
.
If you're running on MacOS using Colima or Docker Desktop, the default VM created might be too small. When running the example scenarios, it starts multiple containers including the 'example' MariaDB databases. Hence, the VM needs more memory (at least 3GB) to avoid having to constrain Recce’s memory usage.
- With Docker Desktop you can adjust using the GUI.
- When using Colima, this can be done by recreating your colima VM with something like the below.
colima delete && colima start --cpu 6 --memory 6
Needs to be more automated. Current we are experimenting with using Reckon to determine versions from flags.
Current release process looks like
- Tag locally and push. This will run a local build; if successful tag the revision and push the tag.
# Minor version (e.g 1.1 -> 1.2) ./gradlew -Preckon.stage=final reckonTagPush # Patch version (e.g 0.6.0 -> 0.6.1) ./gradlew -Preckon.stage=final -Preckon.scope=patch reckonTagPush
- The tag push will trigger a build on GitHub Actions and push to GHCR.
- Create a new release on Github via https://github.com/thoughtworks/recce/releases linked to the tag