I received a report about multiple cases of users clicking
on the unsubscribe link by accident. The unsubscribe action
does not have a confirmation step so the users get instantly
unsubscribed. I do not want to add a confirmation step, so
instead I'm making a few small changes to hopefully reduce
the chances of accidental clicks:
- The footer text now has a "You are receiving this email because..."
blurb to separate the footer a little more from the primary
content
- The unsubscribe link is now a shorter single word: "Unsubscribe",
making it a smaller click target
- the footer now uses a slightly smaller font than the rest of
the email message
The people looking for the unsubscribe link should still be able
to easily find it, but hopefully it should now draw less
"accidental attention".
fetchstatus.py was a Django management command, and is now
a standalone script. This way we avoid doing Django housekeeping
every time it runs (every 10 seconds). It still needs to access
the ALLOWED_HOSTS setting, to make the HTTP request with
a correct Host header.
Fixes: #1071
LINE Notify is shutting down on Apr 1, 2025:
https://notify-bot.line.me/closing-announce
I'm removing the onboarding form so people don't set up new
integrations that will stop working in 5 months.
The code for sending LINE Notify notifications still exists,
and the existing integrations will continue to work (until LINE
Notify stops working).
Also simplify the retry logic: each retry attempt is now
allowed to use the full 30 seconds. This means, a single
webhook delivery can take up to 3*30=90 seconds.
Fixes: #1057
"PRAGMA busy_timeout" configures the database to wait when a
database is locked instead of giving up immediately.
"transaction_mode IMMEDIATE" starts transactions in read/write
mode, required to make busy_timeout work.
Reference: https://gcollazo.com/optimal-sqlite-settings-for-django/
* Remove the --no-loop and --no-threads arguments
* Use a threadpool to do multiple sends concurrently
* Add a new `--num-workers` argument. It limits how many flips we grab
from the database and process concurrently.
* Do not prioritize flips with historically low send times any more
(not as important now with concurrent sending, and simpler this way)
* Workers close db connections when they finish
(to keep the number of idle connections low)
Note: concurrent.futures.ThreadPoolExecutor internally has an unbounded
queue, it will accept any amount of jobs and keep them queued. We don't
want that. We only want to grab a flip, and commit to processing it,
if we know there's a free worker for it. Therefore we're tracking the
number of jobs in flight using a semaphore (`self.seats`).
Commit 8fed685f12 added a HEALTHCHECK
instruction in the Dockerfile. The healthcheck script calls http://localhost:8000/api/v3/status/, which fails if localhost is not in ALLOWED_HOSTS.
With this change, the healthcheck script is now a Django management
command. It reads Django's ALLOWED_HOSTS setting, grabs the first
element, and uses it in the "Host:" HTTP header when making a HTTP
request.
cc: #1051
This commit adds a HEALTHCHECK instruction in Dockerfile.
The HEALTHCHECK instruction calls /docker/fetchstatus.sh
which in turn makes a HTTP request to
http://localhost:8000/api/v3/status/
This endpoint makes a test database query and returns non-200
response if the query fails. So, in short, if the Healthchecks
container for any reason is unable to query database, `docker ps`
will now show the container as "unhealthy".
cc: #1045
The API responses already contain ping_url, update_url, resume_url,
pause_url fields where the UUID can be extracted from, so we are
not exposing new information. The extraction can be finicky in,
say, shell-scripting scenarios. So for API user convenience we will
now also provide the check's code (UUID) as a separate field.
Fixes: #1007
We already have a MS Teams integration but MS Teams is discontinuing
the incoming webhook feature used by this integration:
https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/
MS Teams now recommends to use Workflows to post messages
via webhook. MS Teams does not provide backwards compatibility or
an upgrade path for existing integrations.
This commit adds a new "msteamsw" integration which uses MS Teams
Workflows to post notifications. It also updates the instructions
and illustrations in the "Add MS Teams Integration" page.
cc: #1024
Defer loading body_raw, instead load its first 150 bytes
as "body_raw_preview". This reduces both network I/O to database,
and disk I/O on the database host if the database contains large
request bodies.
cc: #1023
There are three related changes:
* Removed legacy timezones from hc.lib.tz.all_timezones
* Added data migration to update existing Check.tz values
* For backwards compatibility, added code to automatically
replace a legacy timezone with a canonical timezone when a
legacy timezone is passed to an API call
I used the timezone mapping on
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones