Hydra is a full-fledged framework for building web services, multithreaded and concurrent applications with SQL and KV DB support. It's currently moving to the production-ready state
Go to file
2020-07-25 22:39:45 +07:00
app Merge branch 'labyrinth_map' 2020-07-25 22:39:45 +07:00
catalogue KV DB WIP 2019-08-12 01:37:54 +07:00
lib Merge branch 'labyrinth_map' 2020-07-25 22:39:45 +07:00
.DS_Store trail and starting lab edits 2020-07-20 11:01:30 -04:00
.ghci Hydra Framework: initial commit. 2019-05-02 00:12:50 +07:00
.gitignore Massive reorganizing: subprojects 2020-05-09 01:35:20 +07:00
astro.db WIP 2020-02-03 00:32:40 +07:00
LICENSE Initial commit 2019-05-02 00:15:45 +07:00
meteor_counter.cfg Fixed a hang bug. 2020-03-26 21:55:37 +07:00
perf_test_app2.cfg Additional perf testing app added 2020-05-08 23:53:45 +07:00
perf_test_app.cfg MeteorCounter app updated. Free & Church versions 2019-05-17 02:39:06 +07:00
README.md Testing hello 2020-06-19 22:15:58 +07:00
Setup.hs Hydra Framework: initial commit. 2019-05-02 00:12:50 +07:00
stack.yaml Restructuring WIP 2020-07-17 22:33:44 +07:00

Hydra Framework

All-in-one framework for writing Haskell apps which use the following features out of the box:

  • Multithreading
  • Safe STM-powered concurrency
  • KV DB functionality (Redis & RocksDB backends supported)
  • SQL DB functionality (beam incorporated, SQLite supported, PG & MySQL possible)
  • CLI apps support
  • Logging
  • Random data generation
  • Many others

With the framework, you can create complex applications that have a good maintainability, testability, simplicity, that have a good structure and are easy to read and change. The key principles in the framework:

  • Layered architecture
  • Separation of Subsystem Interfaces, Business Logic, Runtime and Implementation
  • Convenient and simple to use eDSLs for Business Logic
  • Layered structure of business application: State, Domain, Business Logic

The Hydra Project

This project demonstrates the principles of Software Design and Architecture in pure Functional Programming. It provides a framework implemented with several different approaches for easy comparison:

  • Final Tagless
  • Free Monad
  • Church Encoded Free Monad

The core idea of the Free monadic frameworks is known as Hierarchical Free Monads.

The project is a showcase for my book Functional Design and Architecture. The approaches presented in Hydra are well-described and rationalized in the book, so you may obtain even more info about best practices and ideas of how to write a good Haskell code.

Building dependencies

Ubuntu:

$ sudo apt-get install libpg-dev librocksdb-dev

Building and running

Use stack for building all the framework and apps:

$ stack build

You can also switch the optimizations off and use several threads for building:

$ stack build --fast -j4

Running a project is also simple:

$ stack exec labyrinth

To load a subproject into GHCi, use the following command:

$ stack ghci labyrinth:exe:labyrinth

Sample applications

There are 3 sample applications:

  • Astro app: web server (with servant) and CLI client tool which allows to track meteors (tool for astronomers).
  • PerfTestApp: an application you can run to measure the performance of the three engines.
  • PerfTestApp2: another application you can run to measure the performance of the three engines.
  • MeteorCounter: application which demonstrates the usage of STM and multithreading using three engines.
  • Labyrinth: a game about exploring the labyrinth with a CLI interactive interface.

Code samples

createMeteor :: MeteorTemplate -> D.SqlConn BS.SqliteM -> L.AppL MeteorId
createMeteor mtp@(MeteorTemplate {..}) conn = do
  L.logInfo $ "Inserting meteor into SQL DB: " <> show mtp

  let time = Time.UTCTime (toEnum 1) (Time.secondsToDiffTime 0)

  doOrFail
    $ L.scenario
    $ L.runDB conn
    $ L.insertRows
    $ B.insert (SqlDB._meteors SqlDB.astroDb)
    $ B.insertExpressions
          [ SqlDB.Meteor B.default_
            (B.val_ size)
            (B.val_ mass)
            (B.val_ azimuth)
            (B.val_ altitude)
            (B.val_ time)
          ]

  let predicate meteorDB
          = (SqlDB._meteorSize meteorDB     ==. B.val_ size)
        &&. (SqlDB._meteorMass meteorDB     ==. B.val_ mass)
        &&. (SqlDB._meteorAzimuth meteorDB  ==. B.val_ azimuth)
        &&. (SqlDB._meteorAltitude meteorDB ==. B.val_ altitude)

  m <- doOrFail
    $ L.scenario
    $ L.runDB conn
    $ L.findRow
    $ B.select
    $ B.limit_ 1
    $ B.filter_ predicate
    $ B.all_ (SqlDB._meteors SqlDB.astroDb)
  pure $ SqlDB._meteorId $ fromJust m

Additional materials

Checkout the following materials to learn more about he Hierarchical Free Monads approach used in Hydra:

Hello!