Extract garbage collection tasks to their own functions

This simplifies the GC loop, and lets us refactor those functions
independently, or break them out.
Add error handling to garbage collection tasks

This helps to make them more standalone, to more easily refactor the way
they're managed and invoked.
Use at-at to schedule garbage collection tasks

This relieves us from having to manage the lifecycle of these tasks
ourselves. It also makes them more flexible, by decoupling each task
from the others and making them properly asynchronous.

                  ________
              _,.-Y  |  |  Y-._
          .-~"   ||  |  |  |   "-.
          I" ""=="|" !""! "|"[]""|     _____
          L__  [] |..------|:   _[----I" .-{"-.
         I___|  ..| l______|l_ [__L]_[I_/r(=}=-P
        [L______L_[________]______j~  '-=c_]/=-^
         \_I_j.--.\==I|I==_/.--L_]
           [_((==)[`-----"](==)j
              I--I"~~"""~~"I--I
              |[]|         |[]|
              l__j         l__j
              |!!|         |!!|
              |..|         |..|
              ([])         ([])
              ]--[         ]--[
              [_L]         [_L]  -Row
             /|..|\       /|..|\
            `=}--{='     `=}--{='
           .-^--r-^-.   .-^--r-^-.
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                __               __
         ____ _/ /_       ____ _/ /_
        / __ `/ __/______/ __ `/ __/
       / /_/ / /_ /_____/ /_/ / /_
       \__,_/\__/       \__,_/\__/
Convert TTLs to seconds before passing them to garbage collect functions

There's no need to do this every time. May as well simplify those
functions a bit.
Use Period objects for representing time settings

This lets us basically avoid having to track whether these have been
parsed/munged and what their units are, because we can just check that
they're Periods. It also lets us simplify a bit of code turning them
into seconds unnecessarily.
Add automatic compression of the dead-letter office

Prior to this, there was no self-management of the DLO. If messages went
into it, they were never removed or dealt with unless by the user. This
meant that a user with a lot of failures, who didn't know about the DLO,
could have their storage eaten up the messages (which were effectively
useless, since they didn't know about them). Now the DLO will be
periodically compressed (per the `dlo-compression-threshold` setting).
Any messages older than the threshold will be compressed into a .tgz
file. This runs on startup and periodically according to the
`gc-interval`, but will only produce one .tgz file per threshold period.
Any other messages will have their compression deferred until the next
period begins.
Fix use/require in command test
Specify encoding when creating tarballs

This was failing with the error "This archives contains unclosed
entries.", because we were calling `count` on a string to get the number
of bytes, without specifying the encoding to use. Now, encoding is a
required parameter for `add-entry` and `tar`, and is used to determine
the length of the data to be written.
Add metrics for DLO size and compression

This adds global and command-specific metrics for the dead-letter
office, including number of messages, number of archives, space usage on
disk, number of failures, and compression time. Overall values for
compression time, space usage, and number of messages are exposed via
the Dashboard.
Don't use a redundant file-filter for compressible-files

The messages function already only returns files with the right file
extension (eg. the messages), so we need only filter by the one property
we care about: compressibility.
Fix docs for archive/add-entry function
Only create DLO metrics once per subdirectory

This was previously creating the metrics every time a message was
discarded or the DLO was stored.
Add tests for DLO metrics
Perform all db maintenance tasks serially

These were being managed individually, since they are logically
distinct, but they require coordinated access to a shared resource (the
db). It's simpler to just run them serially, so we now have a
`perform-db-maintenance!` function, which simply accepts a set of
functions and applies them to the database. This keeps the functions
still primarily distinct, but also runs them the way they need to be
run.

Also reordered the arguments to the db maintenance tasks, since it makes
more sense to partially apply them with a given interval to get a new
maintenance task than to partially apply them with a database.
Merge pull request #464 from nicklewis/compress-dlo

Add automatic compression of the dead-letter office