Skip to content

danne931/akka-dotnet-bank

Repository files navigation

Banking with Akka.NET

Intro

This project utilizes the actor model and event sourcing via Akka.NET to build typical banking functionality. Event sourcing is implemented with Akka.Persistence via PostgreSQL. Akka.Cluster.Sharding is used for the account aggregate root. Future/recurring actor message scheduling with PostgreSQL persistence is established via Quartz.NET.

Use Cases

  1. Deposit
  2. Debit
  3. Registering a transfer recipient internal to the bank
  4. Registering a transfer recipient in a 3rd party bank for domestic transfers
  5. Transferring money to a registered recipient (internal to the bank) debits the sender and credits the receiver
  6. Transferring money to an account in a mock 3rd party bank demonstrates resilience in face of intermittent network issues. Integration with Akka circuit breaker allows pending transfers to be reprocessed once the 3rd party bank is in a healthy state.
  7. Recurring maintenance fee each billing cycle unless a qualified deposit found or a daily account balance threshold met.
  8. Daily debit limit set by the customer
  9. Lock/unlock debit card
  10. Billing statements issued for each billing cycle
  11. Emails sent for account open/close, billing statement, debit declined, & transfer deposited

bank-1-29

UI

The UI is built with React tech for the F# landscape. See Feliz.

SignalR is used to provide feedback from actors to the UI:

  • Overall account state
  • History of transactions on the account
  • Toggling between a transfer sender & receiver account (internal to the bank) demonstrates debits in one account and credits in the other
  • A system operations navbar displays circuit breaker open/closed status for domestic transfers to the 3rd party bank mock server
  • When the circuit breaker closes, pending domestic transfers are reprocessed & corresponding Approved/Rejected events are interpolated into the table

Demonstration

Domestic transfers to a mock 3rd party bank server with circuit breaker integration:

bank-domestic-transfer-1-30

Transfers to accounts internal to the bank:

bank-internal-transfer-Apr-18-2024

Running with Kubernetes via minikube

  1. Dependencies: .NET 8, minikube, pulumi, Node.js 18
  2. sh build.sh -t RunK8sApp
  3. Browser opens automatically after all K8s resources start up
  4. Enable postgres port forwarding if you want to inspect postgres in a local client: sh postgres-port-forward-k8s.sh (Server=postgres;Database=akkabank;Uid=testuser;Pwd=testpass)
  5. View Akka cluster and actor info via Petabridge.Cmd:
    > minikube kubectl -- exec --stdin --tty account-cluster-0 -- /bin/bash
    > dotnet tool run pbm
    > cluster show
    > actor hierarchy
    

Running with Docker

  1. Dependencies: .NET 8, Node.js 18
  2. sh build.sh -t RunDockerApp
  3. Navigate to localhost:3000
  4. If you want to inspect postgres in a dashboard you can visit localhost:5008 (Server=postgres;Database=akkabank;Uid=postgres;Pwd=password)

Running without Docker or K8s

  1. Dependencies: .NET 8, Node.js 18, PostgreSQL & psql
  2. Create a database (Server=localhost;Database=akkabank;Uid=postgres;Pwd=password)
  3. Seed the database: psql postgres < Infrastructure/Migrations/*.sql
  4. cd into ./Web, ./Account.Service, ./Scheduler.Service, & ./MockThirdPartyBankTransferReceiver & dotnet run in each
  5. cd into ./UI and npm run build or npm start

Deploying to Azure AKS

  1. Dependencies: .NET 8, Azure CLI, Pulumi, Node.js 18
  2. sh build.sh -t DeployAllStaging (You will be prompted to sign in to Pulumi & Azure CLI)
  3. One pulumi stack of Azure AKS resources and another Pulumi stack for K8s resources will be created. A Pulumi ESC staging environment will be created and app environment configuration will be set. Your local kubeconfig file will be modified to include details needed to connect to the AKS cluster. See kubectl get all --namespace akkabank & kubectl get all --namespace app-routing-system. App images are currently being pulled from my public docker hub repos. Ingress is partially configured - An IP will be exported to the console when Pulumi finishes creating resources.

Running tests

  1. sh build.sh -t Test

Archive

Inspiration for this project stemmed from reading Functional Programming in C# by Enrico Buonanno.

The first iteration of this project (see CSharpWithLanguageExt directory) expands on Enrico Buonanno's banking account example actor and domain logic to include additional business use cases as well as integration with more tech such as EventStoreDB and the de facto library for functional programming in C#, language-ext.

The second iteration (see FSharpWithAkka directory) is close to a one-to-one representation of the CSharpWithLanguageExt directory, with all use cases rewritten in F# and Paul Louth's echo-process actor library replaced with Akka. I saw that F#'s type inference, computation expressions and immutable data structures made writing programs with typed functional programming more second nature than with C# so I decided to continue with it for the final iteration.