Over the last month or two, I’ve had some unexpected/weird problems building my Haskell projects on Linux – all of a sudden the project would fail to compile fairly innocuous requirements (that had up until that time compiled just fine) and I was very confused. It turns out a change to how the ` Thanks to some users on Github (mkoloberdin offered the workaround and pera noted the commit that likely caused the issue), figured out a fix that seems more permanent.
tl;dr - I added some caching to an app I’m writing in Haskell using Servant. The implementation is pretty naive, but I’ve seen some speedups (as one would expect from skipping a database access), and am glad I was able to build such a simple solution in a language as expressive as haskell. Skip to the end TLDR section to see all the code laid out! FAIR WARNING - this will is NOT an interesting article about caching algorithms or a quirk in GHC or optimization strategies.
tl/dr; I added continuous delivery to my Haskell project (after working through adding CI). The setup is somewhat convoluted, but that’s more due to personal organizational preference. This posts rambles A LOT so feel forward to skip to the end, and check out the config files that made it happen. Here lie my notes from taking my infrastructure for a Haskell-powered application I’ve been working on from Continous Integration (CI) all the way to Continous Delivery (CD).
tl;dr I set up CI on my haskell project, it’s pretty easy if you keep calm and use Gitlab’s CI settings. I hit a few bumps in the road along the way, but you can skip to the end for the completed .gitlab-ci.yml Proselytizing for CI/CD While I don’t think many people need an explanation as to why CI is a good idea, here’s why I’m going for it. As far as I see it, good software engineering as it relates to operations is like a ladder, and here is a non-exhaustive list of rungs, with sophistication/goodness of engineering increasing as I go along:
tl;dr - You may not need a big robust beautifully crafted DB like Postgres every time you build an app. Sometimes SQlite is probably enough. SQLite even provides Full Text Search addons in the way of FTS3/4 and FTS5, so that’s cool too – skim through the article for code snippets on the why/how I’m using SQLite + FTS3/4. If you’re unfamiliar with SQLite, it’s a pretty awesome light-weight SQL-compliant RDBMS.
tl;dr - I moved from server-side stored sessions provided by Network.Wai.Session to client-side signed+encrypted session tokens provided by Wai.ClientSession for my Servant-powered webapp, it’s pretty easy, skim through to see the setup code, /login and /logout code that was required. UPDATE After posting to r/haskell, user u/cocreature pointed out the existence of the servant-auth package – it looks like an awesome solution so also make sure to give that a try before rolling your own.
Static Binaries for a Haskell: A convoluted approach NOTE - this blog post has been updated, thanks to feedback from the reddit community in pointing out ways this should have been done/done better! If you read any part of this with any intent to use it, definitely read the updates at the end! tl;dr - After a bunch of trial and error, I end up building a mostly static binary from a docker container.
tl;dr - It’s pretty easy to use Graylog as a System.Logger backend, check out the code at the end, also if you’re interested in just regular crash-level logging with Servant, there’s some code you might like at the bottom too. On a recent contract I was introduced to Graylog – it’s a pretty awesome log aggregation tool, with a great rontend and I was drawn to the simplicity of use.
tl;dr While the setup works, the most mature haskell library for dealing with webdrivers that I could find wasn’t able to keep up with the changes in Selenium Webdriver :(. Skim through the post to check out the relevant code snippets and tech that made it all (almost) work. If you’re not familiar with Haskell, check it out. This isn’t an introductory type post so it might not be for you, but the language is amazing.
*tl;dr See the code at the end Very often when developing a web application I run into the age-old problem of how to do partial updates. Doing the “U” (Update) in CRUD is actually a little more complicated than just accepting PUTs at some endpoint if you dont’ want to replace the object as a whole. I’ve often worked around this while maintaining somewhere-near spec complicance by just using the catch-all that is POST, and taking whatever object represented the update and doing whatever needed to be done.