Haskell, Redis, Mailgun and Heroku Scheduler
I recently worked on a Haskell application. One aspect of it is a background job that runs hourly. It connects to Redis and sends email using Mailgun. However, Haskell is not a mainstream language so there are not many tutorials of it. It took me quite a while to figure them all out, so I will write one in case it will save anyone’s (e.g. me in the future) time. Oh, and don’t worry to try it out since you can do all of this on Heroku free tier.
First of all, let’s build a fresh Haskell project called
hero with stack.
After that, let’s push our application as is to Heroku. If you read Heroku documentation, it requires a “Buildpack” to setup and deploy your application. Heroku provides official ones for popular frameworks, like Play or Rails. However, they don’t have one for Haskell, so we need either to build one or find one from the community. Fortunately, I found a working Haskell Buildpack, although it’s quite obscure. So we’ll use that when creating a Heroku application.
We can verify that we have a working Haskell application on Heroku by running it on a one-off dyno as follow:
You should see “someFunc” being printed.
Heroku is a fantastic platform. It has quite a number of add-ons. One of it is Heroku Scheduler, an add-on to run arbitrary command on a one-off dyno. It’s not super flexible like cron, but it’s enough for my need. In addition to that, it’s totally free, which is awesome. So, we will use this to schedule our application to run hourly.
The last command should open a page to manage scheduled jobs. Go ahead and add a new job and put
/app/.local/bin/hero-exe +RTS -N as the command to run. The
+RTS -N is a parameter that you give to your Haskell application to enable parallelism by using as many cores as the machine has. Based on my experience, your application will run on an 8 cores machine by Heroku.
Wait until the time your job should be run by the scheduler and verify it by reading the logs:
You should see that “someFunc” is printed, indicating that your application has been scheduled successfully.
Heroku provides Redis in a form of an add-on. It has a generous free plan which gives you 25MB of storage. It, however, doesn’t persist your data on disk. Well, if you use Redis, mostly your use cases are caching. So that should not be a big deal anyway. Let’s add that to our application.
After installing Redis add-on, your application will have an environment variable called
REDIS_URL that you can use to connect to Redis. The format of the value is
redis://<user>:<password>@<domain>:<port>. You could just ignore the
user part since Redis doesn’t have a multi-user access feature.
One Haskell library that I have used successfully to connect to Redis is hedis. It’s simple to use and has a nice tutorial to get you started. Let’s start writing some code for connecting to Redis.
Before compiling the application, you need to add few dependencies in your
hedis is obviously needed, but you also need
network-uri as well. They are used to parse the
Now let’s push that into Heroku to test whether it connects correctly.
You should see the following output indicating that the application has connected correctly to Redis.
Before discovering Mailgun, I used to interface with SMTP directly. Boy, it was a PITA. Few problems arose like your mail provider doesn’t give access because your application is not considered secure and the Haskell library in this area is not good. Mailgun eases the email sending by allowing you to do it via REST API. They also give you a starter domain for testing. So it almost works out of the box, basically.
Haskell, fortunately, has a Mailgun wrapper library called hailgun. The documentation is not as good as hedis since it doesn’t give you any tutorial to get started. It’s quite common in Haskell-land for a library to be documented poorly. However, this library is quite simple that if you just follow the types, you can figure it out easily what to do. But still, a bit of tutorial could save me time here.
So, after setting up a Mailgun account, let’s write some code to test it:
You need to add
either-unwrap in your
hero.cabal file. We don’t need to run this in Heroku for starter. Let’s just run it in GHCi and call the function directly:
You should receive the email in the email you listed as the recipient. You will also get the following output indicating that we have connected succesfully to Mailgun.
Obviously, you don’t want to hardcode your Mailgun credentials in your source code. The best practice is to put it in the environment variables. In Heroku, you can add an environment variable via
heroku config:set <KEY>=<VALUE> command. We can adjust our code accordingly to read the credentials from the environment variables instead.
In this blog post, I have shown you how Haskell can be used for building practical application. All the code above is not intended as production-ready code as it doesn’t handle errors gracefully. I keep it that way for simplicity.
That’s it, folks! Hope it helps.