• Stars
    star
    597
  • Rank 72,033 (Top 2 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created over 2 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

💱 Trading application written in Scala 3 that showcases an Event-Driven Architecture (EDA) and Functional Programming (FP)

trading

CI Elm CI Scala CI Tyrian CI Registry CI Smokey

Reference application developed in the Functional event-driven architecture: Powered by Scala 3 book.

Table of contents

Web App

The web application allows users to subscribe/unsubscribe to/from symbol alerts such as EURUSD, which are emitted in real-time via Web Sockets.

client

It is written in Elm and can be built as follows.

$ nix build .#elm-webapp
$ open result/index.html # or specify browser

There's also a development shell handy for local development.

$ nix develop .#elm
$ cd web-app
$ elm make src/Main.elm --output=Main.js
$ open index.html # or specify browser

If Nix is not your jam, you can install Elm by following the official instructions and then compile as usual.

$ cd web-app
$ elm make src/Main.elm --output=Main.js
$ xdg-open index.html # or specify browser

ScalaJS

There is also a replica of the Elm application written in Scala using the Tyrian framework that can be built as follows.

$ sbt 'webapp/fullLinkJS'

You can then run it via Nix as shown below (it requires flakes).

$ nix run .#tyrian-webapp
Using cache dir: /home/gvolpe/workspace/trading/modules/ws-client/nix-parcel-cache
Server running at http://localhost:1234
✨ Built in 7ms

NOTICE: The nix run command will create a directory for the Parcel cache, which needs write permissions.

We use fullLinkJS to create a fully optimized JS file. However, we can use fastLinkJS for faster iterations.

For such cases, it may be more convenient to use yarn directly.

$ nix develop .#tyrian
$ cd modules/ws-client
$ yarn install
$ yarn build
$ yarn start
yarn run v1.22.17
parcel index.html --no-cache --dist-dir dist --log-level info
Server running at http://localhost:1234
✨ Built in 1.82s

However, this is not fully reproducible and can't be guaranteed this will work in the future.

Without Nix, you need to install yarn and parcel, and use yarn as shown above.

Overview

Here's an overview of all the components of the system.

overview

  • Dotted lines: Pulsar messages such as commands and events.
  • Bold lines: read and writes from / to external components (Redis, Postgres, etc).

Requirements

The back-end application is structured as a mono-repo, and it requires both Apache Pulsar and Redis up and running. To make things easier, you can use the provided docker-compose.yml file.

Build JDK image

The docker-compose file depends on declared services to be published on the local docker server. All docker builds are handled within the build.sbt using sbt-native-packager.

To build all of the service images, we have a few options.

The first one via the given Dockerfile.

$ docker build -t jdk17-curl modules/

The second one via Nix, from where we can build a slim image also based on openjdk:17-slim-buster.

$ nix build .#slimDocker -o result-jre
$ docker load -i result-jre

The third one also via Nix, though building a layered image based on the same JDK we use for development.

$ nix build .#docker -o result-jre
$ docker load -i result-jre

The main difference between these three options is the resulting image size.

$ docker images | rg jdk17
jdk17-curl                    latest               0ed94a723ce3   10 months ago   422MB
jdk17-curl-nix                latest               c28f54e42c21   52 years ago    557MB
jdk17-curl-slim               latest               dbe24e7a7163   52 years ago    465MB

Any image is valid. Feel free to pick your preferred method.

NOTE: As of September 2022, the Docker image resulting from nix build .#docker is no longer compatible with sbt-native-packager, so either go for nix build (defaults to the slim image) or build it directly via Docker with the given Dockerfile.

Build service images

Once the base jdk17-curl image has been built, we can proceed with building all our services' images.

$ sbt docker:publishLocal

Run dependencies: Redis, Kafka, etc

$ docker-compose up -d pulsar redis

pulsar

To run the Kafka Demo (see more below in X Demo), kafka.yml should be used instead.

$ docker-compose -f kafka.yml up

Running application

If we don't specify any arguments, then all the containers will be started, including all our services (except feed), Prometheus, Grafana, and Pulsar Manager.

$ docker-compose up
Creating network "trading_app" with the default driver
Creating trading_pulsar_1 ... done
Creating trading_redis_1  ... done
Creating trading_ws-server_1      ... done
Creating trading_pulsar-manager_1 ... done
Creating trading_alerts_1         ... done
Creating trading_processor_1      ... done
Creating trading_snapshots_1      ... done
Creating trading_forecasts_1      ... done
Creating trading_tracing_1        ... done
Creating trading_prometheus_1     ... done
Creating trading_grafana_1        ... done

It is recommended to run the feed service directly from sbt whenever necessary, which publishes random data to the topics where other services are consuming messages from.

Services

The back-end application consists of 9 modules, from which 5 are deployable applications, and 3 are just shared modules. There's also a demo module and a web application.

modules
├── alerts
├── core
├── domain
├── feed
├── forecasts
├── it
├── lib
├── processor
├── snapshots
├── tracing
├── ws-client
├── ws-server
├── x-demo
└── x-qa

backend

Lib

Capability traits such as Logger, Time, GenUUID, and potential library abstractions such as Consumer and Producer, which abstract over different implementations such as Kafka and Pulsar.

Domain

Commands, events, state, and all business-related data modeling.

Core

Core functionality that needs to be shared across different modules such as snapshots, AppTopic, and TradeEngine.

Feed

Generates random TradeCommands and ForecastCommands followed by publishing them to the corresponding topics. In the absence of real input data, this random feed puts the entire system to work.

Forecasts

Registers new authors and forecasts, while calculating the author's reputation.

Processor

The brain of the trading application. It consumes TradeCommands, processes them to generate a TradeState and emitting TradeEvents via the trading-events topic.

Snapshots

It consumes TradeEvents and recreates the TradeState that is persisted as a snapshot, running as a single instance in fail-over mode.

Alerts

The alerts engine consumes TradeEvents and emits Alert messages such as Buy, StrongBuy or Sell via the trading-alerts topic, according to the configured parameters.

WS Server

It consumes Alert messages and sends them over Web Sockets whenever there's an active subscription for the alert.

Tracing

A decentralized application that hooks up on multiple topics and creates traces via the Open Tracing protocol, using the Natchez library and Honeycomb.

tracing

Tests

All unit tests can be executed via sbt test. There's also a small suite of integration tests that can be executed via sbt it/test (it requires Redis to be up).

X Demo

It contains all the standalone examples shown in the book. It also showcases both KafkaDemo and MemDemo programs that use the same Consumer and Producer abstractions defined in the lib module.

Pulsar CDC

To run the Pulsar CDC Demo, you need Postgres and Pulsar (make sure no other instances are running). Before running them, we need to download the connector NAR file.

$ mkdir -p pulsarconf/connectors && cd pulsarconf/connectors
$ wget https://archive.apache.org/dist/pulsar/pulsar-2.10.1/connectors/pulsar-io-debezium-postgres-2.10.1.nar
$ docker-compose -f pulsar-cdc.yml up

Once both instances are up and healthy, we can run the Pulsar Debezium connector.

$ docker-compose exec -T pulsar bin/pulsar-admin source localrun --source-config-file /pulsar/conf/debezium-pg.yaml

You should see this in the logs.

Snapshot step 3 - Locking captured tables [public.authors]

X QA

It contains the smokey project that models the smoke test for trading.

Monitoring

JVM stats are provided for every service via Prometheus and Grafana.

grafana

Topic compaction

Two Pulsar topics can be compacted to speed-up reads on startup, corresponding to Alert and TradeEvent.Switch.

To compact a topic on demand (useful for manual testing), run these commands.

$ docker-compose exec pulsar bin/pulsar-admin topics compact persistent://public/default/trading-alerts
Topic compaction requested for persistent://public/default/trading-alerts.
$ docker-compose exec pulsar bin/pulsar-admin topics compact persistent://public/default/trading-switch-events
Topic compaction requested for persistent://public/default/trading-switch-events

In production, one would configure topic compaction to be triggered automatically at the namespace level when certain threshold is reached. For example, to trigger compaction when the backlog reaches 10MB:

$ docker-compose exec pulsar bin/pulsar-admin namespaces set-compaction-threshold --threshold 10M public/default

More Repositories

1

nix-config

👾 NixOS configuration
Nix
712
star
2

pfps-shopping-cart

🛒 The Shopping Cart application developed in the book "Practical FP in Scala: A hands-on approach"
Scala
516
star
3

pfps-examples

🏮 Standalone examples shown in the book "Practical FP in Scala: A hands-on approach"
Scala
189
star
4

dconf2nix

🐾 Convert Dconf files (e.g. Gnome Shell) to Nix, as expected by Home Manager
Nix
179
star
5

advanced-http4s

🌈 Code samples of advanced features of Http4s in combination with some features of Fs2 not often seen.
Scala
142
star
6

sbt-nix.g8

❄️ Get started with Nix in Scala
Nix
115
star
7

scalar-feda

Scala
96
star
8

http4s-good-practices

Collection of what I consider good practices in Http4s (WIP)
75
star
9

neovim-flake

Nix flake for Neovim & Scala Metals
Nix
73
star
10

shopping-cart-haskell

💎 Haskell version of the Shopping Cart application developed in the book "Practical FP in Scala: A hands-on approach"
Haskell
65
star
11

musikell

🎸 Artists, Albums and Songs represented using Neo4j + GraphQL
Haskell
55
star
12

newtypes

Zero-cost wrappers (newtypes) for Scala 3
Scala
41
star
13

exchange-rates

💱 Querying a rate-limited currency exchange API using Redis as a cache
Haskell
41
star
14

light-play-rest-api

This project aims to be the reference to create a Light Weight REST API using Play Framework 2.4.x.
Scala
35
star
15

vim-setup

👾 My NeoVim configuration for Scala & Haskell development (permanently moved to https://github.com/gvolpe/dotfiles)
Vim Script
30
star
16

fts

🔍 Postgres full-text search (fts)
Haskell
28
star
17

classy-optics

🔎 Source code shown at my talks at Scale by the Bay 2018 and Scalar 2019
Scala
26
star
18

haskell-book-exercises

From the book "Haskell Programming from first principles"
Haskell
26
star
19

stm-demo

Bank transfer examples using STM in both Haskell and Scala (zio-stm)
Scala
17
star
20

postgresql-resilient

Automatic re-connection support for PostgreSQL.
Haskell
16
star
21

akka-cluster-demo

Testing the Akka 2.4 feature "akka.cluster.sharding.remember-entities"
Scala
15
star
22

nmd

NixOS Module Documentation generator
Nix
15
star
23

social-graph-api

Authentication & Social Graph API built on top of Redis, Neo4J and Play!
Scala
13
star
24

fsm-streams

Scala
13
star
25

BeautyLine

https://www.gnome-look.org/p/1425426/
12
star
26

hll-algorithm-sample

HLL Algorithm and Web Scraping sample
Scala
11
star
27

simple-http4s-api

Just a simple API using "http4s" and Json support on top of Play Json and Circe
Scala
11
star
28

effects-playground

🎯 Learning different effect systems by example
Haskell
11
star
29

types-matter

Examples shown in my talk "Why types matter". See also https://github.com/gvolpe/par-dual
Haskell
10
star
30

split-morphism

➰ Split Morphisms
Haskell
10
star
31

stargazers-raffle

Run a raffle among the 🌟 stargazers 🌟 of a Github project!
Scala
10
star
32

akka-stream-full-project

Complete project using Akka Stream with Error Handling and ~100% Test Coverage
Scala
9
star
33

cats-functional-data-validation

Functional Data Validation in Scala using the Cats library
Scala
8
star
34

cats-effect-demo

Code samples for the use cases given at my Dublin Scala Meetup's talk
Scala
8
star
35

typed-actors-demo

Simple demo using Typed Actors by @knutwalker
Scala
8
star
36

bookies

My solution to a coding challenge
Scala
7
star
37

users-api-test

Basic Users API including Authentication using Http4s v0.18 and Cats Effect v0.5
Scala
6
star
38

falsisign.nix

Nix derivations for falsisign. Save trees, ink, time, and stick it to the bureaucrats!
Nix
5
star
39

learning-haskell

Learning Haskell
Haskell
4
star
40

http4s-crud-demo

CRUD operations and Error Handling using Http4s
Scala
4
star
41

dependent-types

Personal notes taken from the course ThCS. Introduction to programming with dependent types in Scala.
Scala
4
star
42

par-dual

🔁 ParDual class for a Parallel <-> Sequential relationship
Haskell
4
star
43

advanced-scala-exercises

Solved exercises of the Advanced Scala with Scalaz book by Noel Welsh and Dave Gurnell
Scala
4
star
44

social-network

Social Network example Twitter-alike (followers / following) implemented on top of Titan Db
Scala
4
star
45

eta-servant-api

Simple Servant REST Api working on ETA (https://eta-lang.org/)
Haskell
4
star
46

scala-lab

Playground for Scala 3's experimental features
Scala
4
star
47

http4s-auth

Authentication library for Http4s
Scala
3
star
48

reader-monad-sample

Example of Dependency Injection in Scala with Reader Monads
Scala
3
star
49

nixos-hyprland

NixOS on Wayland / Hyprland
Nix
3
star
50

classy-lens

Photography website
CSS
3
star
51

truco-argentino

Classic card games
C++
3
star
52

optics-exercises

Book exercises
Haskell
3
star
53

gvolpe-bot

Telegram Bot built using the Canoe library
Scala
3
star
54

functional-chain-of-responsibility

Functional Chain of Responsibility pattern
Scala
3
star
55

problem-solving

Just having fun solving algorithmic problems in λ Haskell & Scala
Haskell
3
star
56

idris-dependent-types

Dependent Types research in the Idris language
Idris
3
star
57

pricer-streams-demo

Scalaz Streams demo project
Scala
3
star
58

free-monad-example

Simple example of a Custom Free Monad Coyoneda using Scalaz.
Scala
2
star
59

shapeless-demo

Shapeless playground
Scala
2
star
60

play-cors-filter

Play! Framework API with CORS Filter
Scala
2
star
61

coursera-reactive-prog

Curso online de programación reactiva https://www.coursera.org/course/reactive
Scala
2
star
62

simple-file-reader-akka-actors

Simple file reader using Akka actors in Scala
Scala
2
star
63

pricer-fs2-demo

Demo project using FS2 (Functional Streams for Scala)
Scala
2
star
64

free-as-a-monad

Running 2 or more algebras with Coproduct and Inject when using the Free Monad
Scala
2
star
65

blog

Principled Software Craftsmanship
SCSS
2
star
66

logger-writer-monad

Pure functional log of transactions using the Scalaz Writer Monad.
Scala
2
star
67

play-oauth-silhouette

Example using OAuth with Play! Framework and Silhouette
Scala
2
star
68

cloud-haskell-demo

Getting Started with Cloud Haskell
Haskell
1
star
69

rate-limiter

Haskell
1
star
70

play-2.5.0-M1-streams

Exploring the integration of Akka Stream included in the first milestone version of Play! 2.5.0
Scala
1
star
71

ytui-music-nix

Nixified ytui-music client
Nix
1
star
72

running

A personal running program to train for a 10k run and a half marathon
1
star
73

scalaz-streams-playground

Playing around with Scalaz Streams
Scala
1
star
74

di-macwire-sample

Example of Dependency Injection in Scala using Macwire.
Scala
1
star
75

haskell-sample-box

Collection of useful stuff learned day by day.
Haskell
1
star
76

amqp-demo

Haskell
1
star
77

streaming-playground

Haskell
1
star
78

neovim-coc

My previous NeoVim configuration with CoC for LSP support
Vim Script
1
star
79

steward

Run Scala Steward on my repos
1
star
80

cake-pattern-sample

Example of Cake pattern implementation in Scala.
Scala
1
star
81

slides

1
star
82

redis-scala-script

Redis massive data update with transactions built on top of SCRedis.
Scala
1
star
83

servant-api

Simple API built using Servant
Haskell
1
star
84

functional-data-validation

Functional Data Validation in Haskell (Examples of my talk in Eindhoven, NL on June 2017)
Haskell
1
star
85

bazecor-nix

Nix flake for Bazecor
Nix
1
star
86

transient-demo

Some computational examples using the Transient library
Haskell
1
star
87

play-web-sockets

Example using Web Sockets in Play! Framework 2
Scala
1
star
88

phantom-ssl-extension

Extension for the Cassandra client phantom supporting SSL connections and username / password authentication for Java 8.
Scala
1
star
89

pipes-concurrency-tutorial

Pipes Concurrency Tutorial personal notes
Haskell
1
star
90

pipes-tutorial

Haskell Pipes Tutorial personal notes
Haskell
1
star
91

link-checker-akka

Example of a link checker using the actor model of Akka provided by Roland Kuhn in the Reactive Programming course on Coursera.
Scala
1
star
92

events-processor-prototype

Reactive consumer of events coming from a Rabbit MQ queue using Akka streams.
Scala
1
star
93

bash-scripting

Generic Bash Scripting & Utilities that I've been creating for repetitive tasks.
Shell
1
star
94

summoner-benchmarks

Source code for the benchmarks published in my blog
Scala
1
star
95

mtl-generic-reader

Exploring the idea of deriving `cats.mtl.ApplicativeAsk` instances for `zio.Task` and `cats.effect.IO` in a principled way.
Scala
1
star
96

gvolpe-website

Source code to generate the static website https://gvolpe.com/
JavaScript
1
star
97

computation-expressions-demo

Simple comparison of the use of the standard Scala Future and the scala async library for asynchronous computation.
Scala
1
star
98

monocle-lenses

Using Monocle lenses to modify nested properties in case classes
Scala
1
star
99

medellin-talk

Haskell
1
star
100

vim-scala

Basic Scala 3 syntax support built on top of Derek Wyatt's work on vim-scala
Vim Script
1
star