DEV Community

loading...

Hangfire w/ Mongo using Docker

Nuno Reis
I'm a software developer from Portugal currently working in a big tech company dealing with fashion called Farfetch.
Originally published at Medium Updated on ・5 min read

This article is a basic tutorial on how to setup Hangfire using a dotnet core application.

Before I start rambling, what is Hangfire and what does it do?

Hangfire is an easy way to perform background processing in .NET and .NET Core applications. No Windows Service or separate process are required. It is also backed by persistent storage. It’s great for long running tasks where you have multiple instances of an application and you need or want to start or stop those tasks.


Let’s Start

First we need to choose a database that is compatible with Hangfire. I chose MongoDB because it’s free, but SQL Server is also compatible.

Step 1: Create a docker-compose file

This docker compose will be responsible to create our mongo database. I’ve also added mongo-express to visualize our mongo db on the browser and a beautiful little script runner to create our user with access to the database.

version: '3'
services:
 mongo:
  image: mongo:3.4.14
  container_name: mongo
  environment:
   - MONGO_INITDB_ROOT_USERNAME=admin
   - MONGO_INITDB_ROOT_PASSWORD=admin
  ports:
   - 27017:27017
  restart: unless-stopped
 mongo-express:
  image: mongo-express
  container_name: mongo_express
  ports:
   - 8081:8081
  environment:
   ME_CONFIG_MONGODB_ADMINUSERNAME: admin
   ME_CONFIG_MONGODB_ADMINPASSWORD: admin
  restart: always
 mongo-scripts:
  image: mongo-scripts
  container_name: mongo_scripts
  environment:
   - SERVER=mongo
   - PORT=27017
   - DATABASE=HANGFIRE_TUTORIAL
   - USERNAME=myuser
   - PASSWORD=pwd
  build:
   context: .
   dockerfile: Dockerfile
  depends_on:
   - mongo
Enter fullscreen mode Exit fullscreen mode

If you are new to docker compose files, you can read about it here.

Step 2: Create a Dockerfile

We will need to create the Dockerfile in the same space of the docker compose file with the following:

FROM mongo:3.4.14
ARG SERVER
ARG PORT
ARG DATABASE
ARG USERNAME
ARG PASSWORD
WORKDIR mongoscripts
COPY . .
RUN tr -d '\r' <run-mongoscripts.sh >run-mongoscripts.sh.tmp && mv -f run-mongoscripts.sh.tmp run-mongoscripts.sh
CMD sh run-mongoscripts.sh ${SERVER} ${PORT} ${DATABASE} ${USERNAME} ${PASSWORD}
Enter fullscreen mode Exit fullscreen mode

This Dockerfile is responsible for copying our bash script and execute it.

Step 3: Create a bash script

The bash script name should be equivalent to the one given in the Dockerfile. The name I gave it was run-mongoscripts.sh and it should be in the same space as the docker compose file.

The bash script should have the following:

#!/bin/sh
main() {
 server=$1;
 port=$2;
 database=$3;
 username=$4;
 password=$5;
 workTime=1;
 totalTimes=50;
 numberOfChecks=1
 while [ $numberOfChecks -le $totalTimes ] &&
   ! timeout "$workTime" bash -c "echo > /dev/tcp/$server/$port";
 do
   echo "$server:$port is DOWN after $numberOfChecks check";
   sleep $workTime;
   numberOfChecks=$(($numberOfChecks + 1));
 done;
 if ! timeout "$workTime" bash -c "echo > /dev/tcp/$server/$port";
 then
  echo "$server:$port is DOWN after all checks";
  exit 1;
 else
  echo "$server:$port is UP";
 fi

 mongo --host $server --port $port admin -u admin -p admin --eval "db.getSiblingDB('$database').createUser({user:'$username',pwd:'$password',roles:[{role:'readWrite',db:'$database'}]})"
}
main "$@";
Enter fullscreen mode Exit fullscreen mode

This script is responsible for creating a user capable of reading and writing in a mongo database of our choosing. It contains a loop for it to wait until the mongodb container is up.

Ok, the worst is over. 😅

Now we can run our docker compose file using this command where the docker compose file is:

docker-compose up -d --build

Go to your browser and you will be able to access mongo-express on http://localhost:8081/.

We finally have our setup complete. 🎉

Step 4: Create a new ASP.NET Core Web API

Open Visual Studio and create a new project using the following templates:

Step 5: Add Hangfire to our project

After our ASP.NET Core Web API has been created, let’s proceed to the installation of Hangfire into our project. Head out to our .csproj and add the following:

<ItemGroup>
  <PackageReference Include="Hangfire" Version="1.7.9" />
  <PackageReference Include="HangFire.Mongo" Version="0.6.6" />
</ItemGroup>
Enter fullscreen mode Exit fullscreen mode

These are all the packages we are going to need so now we can add our connection string to Mongo DB to feed onto Hangfire.

Step 6: Add MongoDB connection string

Mongo’s template connection string should look like this:

mongodb://<username>:<password>@<host>:<port>/<database>

Let’s add it into appsettings.json using our settings:

{
  ...
  "ConnectionStrings": {
    "HangfireConnection":
      "mongodb://myuser:pwd@localhost:27017/HANGFIRE_TUTORIAL"
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Configure Hangfire

After that we can start to add our dependencies to the Startup.cs file located at the root of the project.

You will have two methods. ConfigureServices and Configure. ConfigureServices is used to add services to the container for them to be available for dependency injection. Configure is where we set up the middlewares that handle every HTTP request.

So, in ConfigureServices we will add our dependency to Hangfire like this:

var options = new MongoStorageOptions
{
  MigrationOptions = new MongoMigrationOptions
  {
    BackupStrategy = MongoBackupStrategy.None,
    Strategy = MongoMigrationStrategy.Drop
  }
};

services.AddHangfire(x => x.UseMongoStorage(
    Configuration.GetConnectionString("HangfireConnection"),
    options));
Enter fullscreen mode Exit fullscreen mode

And in Configure we will add this so that we can open the Hangfire Dashboard and to be able to schedule jobs and stop them.

app.UseHangfireDashboard()
   .UseHangfireServer();
Enter fullscreen mode Exit fullscreen mode

Awesome. Now we can just run our application and go to /hangfire and we will be able to see this beautiful dashboard.

We now have our Hangfire configured and ready to go.

Step 8: Add a Job to Hangfire

Our next step will be to add a job to execute every day at 8AM to tell us good morning.

In our Startup.cs file, on the Configure method, we will add this:

RecurringJob.AddOrUpdate<HangfireJobs>(
   "GoodMorning",
   x => x.GoodMorning(),
   Cron.Daily(8));
Enter fullscreen mode Exit fullscreen mode

So, what does this do? This tiny method will add a recurring job to Hangfire that will execute the method GoodMorning declared on the class HangfireJobs every day at 8AM identified in the last argument.

Next Step will be to create the class HangfireJobs and its method, GoodMorning.

public class HangfireJobs
{
   public void GoodMorning()
   {
     Console.WriteLine("Good Morning!");
   }
}
Enter fullscreen mode Exit fullscreen mode

After this, we can run our app and go to /hangfire/recurring and see this job waiting for it to be ran. It should look something like this.


Wrap up

This is it. Now you have a functioning application using Hangfire with Mongo DB using Docker where you can add Jobs to run whenever you want and how many times you need.

If you want to follow up on something more, here is some links that may be helpful:

Discussion (0)