This is a small toy project for processing payment transactions from a CSV file.
The project showcases the Rust programming language and best practices related to code quality and testing.
This diagram shows the high level components of the application. Obviously for this exercise we don't have a truly distributed system but the concepts are meant to show the start of a scalable design.
For the purposes of this toy application, the CLI and local filesystem will be the only implemented path through the system.
CLI
is the main entry point of the application for the purposes of this toy projectOther Clients
is meant to show that other hypothetical clients can consume the ingestion api with different URI schemesIngestion Service
exposes a URI based interface for submitting a payments CSV for processing- Files can be read from either local filesystem or other storage mechanisms
Payments Queue
is a thread-safe mechanism to queue payments that are ready for processingPayment Processor
's are a pool of workers available to process payments and output results
- The application is designed to be easily testable by using dependency injection and SOLID principles
- The parallelism of the application was meant to show scalability and understanding of advanced Rust programming, but actually introduced a ton of complexity related to the chronological order of transactions.
- All errors are mapped to some variation of the global error type
PaymentError
so you can use?
throughout the application. - I am using
panic!()
if there is an irrecoverable error, wouldn't do this in a production application
- Unit tests exist in the source files and focus on isolated components of the system
- Integration tests also exist that treat the entire payment engine as a blackbox and there are input files used for testing under
tests/resources
Run with cargo:
$ cargo run -- transactions.csv > accounts.csv
Input: (trasnsactions.csv)
type,client,tx,amount
deposit,1,1,1.0
deposit,2,2,2.0
deposit,1,3,2.0
withdrawal,1,4,1.5
withdrawal,2,5,3.0
deposit,3,6,37.0
dispute,3,6,
chargeback,3,6,
dispute,1,1,
resolve,1,1,
Output (accounts.csv):
client,available,held,total,locked
3,0,0,0,true
2,2,0,2,false
1,1.5,0,1.5,false
- Truncate floats at 4 past decimal or round the value? (assuming rounding)
- Do client ID's need to match for disputed transactions? (assuming yes)
- Should accept "blank" values for disputes/chargebacks/resolves? (assuming yes)
- Can you dispute both deposits and withdrawals? (assuming yes, but this is a guess)
- In case of disputing a deposit, subtract disputed amount from available and add to held
- In case of disputing a withdrawal, add disputed amount to held but do not increase available
- How do chargebacks work in case of disputing withdrawal?
- How do resolves work in case of disputing withdrawal?
- Should all transactions fail if account frozen? (assuming yes)