Skip to content

Commit

Permalink
Added jobs documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
zacwood9 committed Jan 25, 2021
1 parent 037835b commit c6d9484
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 11 deletions.
3 changes: 2 additions & 1 deletion Guide/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ HTML_FILES+= database-migrations.html
HTML_FILES+= tailwindcss.html
HTML_FILES+= npm.html
HTML_FILES+= elm.html
HTML_FILES+= jobs.html

all: $(HTML_FILES) bootstrap.css instantclick.js

Expand All @@ -43,7 +44,7 @@ all: $(HTML_FILES) bootstrap.css instantclick.js

watch: all
@echo "Server is starting at: http://localhost:3000/index.html"
@nix-shell -p haskellPackages.wai-app-static --command "warp" &
@nix-shell -p haskellPackages.wai-app-static --command "warp" &
@ls *.markdown layout.html | entr make

clean:
Expand Down
89 changes: 89 additions & 0 deletions Guide/jobs.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Jobs

```toc
```

## Introduction

IHP has built-in functionality for creating and running background jobs. Jobs are perfect for any tasks that can be split up into small units and run in parallel, such periodically cleaning the database, sending emails, and scraping data.

### Creating a job

In the codegen tool in the IHP IDE, use the "Background Job" option to generate the code for a new job. To illustrate the features of jobs, let's
create a job to send an email to our application's customers.

### Implementing the job

The job file is created at `<Application>/Job/<Name>.hs`, and looks like:

```haskell
module Web.Job.EmailCustomers where
import Web.Controller.Prelude

instance Job EmailCustomersJob where
perform EmailCustomersJob { .. } = do
putStrLn "Hello World!"
```

The type `EmailCustomersJob` is a generated type based on the table the background job codegen added to `Schema.sql`. If you want to include additional data in the job, you can add rows to the table in the IHP IDE just like any custom table.

A pseudocode implementation of a job that sends a marketing email to all of the customers:

```haskell
module Web.Job.EmailCustomers where
import Web.Controller.Prelude

instance Job EmailCustomersJob where
perform EmailCustomersJob { .. } = do
customers <- query @Customer |> fetch
mapM_ (\customer -> sendMail (MarketingMail customer)) customers
```

### Running the job

IHP watches the job table in the database for any new records and automatically run the job asynchronously when a new job is added. So to run a job, simply create a new record:

```haskell
newRecord @EmailCustomersJob |> create
```

This can be done in a controller action or in a script as will be shown below.

#### Development vs. Production

In development mode, these watchers are started with the dev server. In production however, use `make build/bin/RunJobs` to build a binary that you can deploy along side your IHP app to watch for added jobs and run them.

### Viewing job status

A benefit of jobs compared to just running scripts is info about the jobs is stored persistently in the database. To see the status of a job, inspect it's `#status` field. If the job failed, you can see the error that caused it to fail in the field `#lastError`.

### Scheduling jobs with cron

IHP does not (yet) have built-in functionality to schedule jobs to run on a regular basis. Instead we can build a binary that will start a job with an IHP script and use `cron` to schedule the binary to run daily, hourly, or whatever your use case requires.

Generate a new script with the "Script" option in the IHP IDE codegen tool. In the generated file `Application/Script/<Script Name>.hs`, simply create a job record as described above:

```haskell
#!/usr/bin/env run-script
module Application.Script.RunEmailCustomersJob where

import Application.Script.Prelude

run :: Script
run = do
newRecord @EmailCustomersJob |> create
pure ()
```

Build this script into a binary with `make build/bin/Script/RunEmailCustomersJob` as described in the [scripts documentation](/Guide/scripts.html).

We can then create a cron entry such as

```
0 5 * * * root bin/Script/RunEmailCustomersJob
```

to schedule a job to be run every day at 5am. See [this article by DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-use-cron-to-automate-tasks-ubuntu-1804) for more information on `cron`.


21 changes: 11 additions & 10 deletions Guide/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@
<a class="nav-link secondary" href="scripts.html">Scripts</a>
<a class="nav-link secondary" href="debugging.html">Debugging</a>
<a class="nav-link secondary" href="testing.html">Testing</a>

<a class="nav-link secondary" href="editors.html">Editors & Tooling</a>



<a class="nav-link headline" href="mail.html">Advanced</a>
<a class="nav-link secondary" href="mail.html">Sending Mail</a>
<a class="nav-link secondary" href="jobs.html">Jobs</a>
<a class="nav-link secondary" href="updating.html">Updating IHP</a>
<a class="nav-link secondary" href="auto-refresh.html">Auto Refresh</a>
<a class="nav-link secondary" href="package-management.html">Package Management</a>
Expand Down Expand Up @@ -103,7 +104,7 @@
{{& output }}
</main>



<style>
html, body {
Expand Down Expand Up @@ -189,30 +190,30 @@

.source-code {
background-color: #002b36;

border-radius: 3px;
}
.language-haskell, .language-bash, .language-sql, .language-html, .language-nix, .language-css, .language-javascript, .language-makefile {
color: #839496 !important;
display: block;
padding: 1rem;
}

code {
background-color: rgba(0, 43, 54, 0.11);
color: #002b36 !important;
}

code .cr {
color: #93a1a1 !important;
font-weight: bold;
}

code .kw, code .kw, code .kw { color: #859900; }
code .st { color: #2aa198; }

pre { overflow: scroll; }

img { max-width: 100%; }

/* TOC */
Expand Down

0 comments on commit c6d9484

Please sign in to comment.