summaryrefslogtreecommitdiff
path: root/scripts/cron_daily.sh
blob: 9fb0b449232e85d4400b0a21555fa2dbbb3361d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env bash
# VPS wrapper for cron: download the latest trading day into a daily snapshot file, keep only
# recent snapshots, and send an e-mail when something goes wrong.
#
#   crontab (UTC; Taipei = UTC+8):
#     ALERT_TO=you@example.com
#     30 6  * * 1-5  $HOME/stock/scripts/cron_daily.sh
#     0  11 * * 1-5  $HOME/stock/scripts/cron_daily.sh
#
# Environment: STOCK_DIR (default ~/stock), KEEP_DAYS (default 30), ALERT_TO (e-mail address;
# needs msmtp or mail). Snapshots go to $STOCK_DIR/updates/YYYY-MM-DD.csv, the log to
# $STOCK_DIR/logs/daily.log. Failures: download failed after all retries, or no new data for 10 days.
set -u
root=${STOCK_DIR:-$HOME/stock}
keep_days=${KEEP_DAYS:-30}
updates="$root/updates"; logs="$root/logs"; log="$logs/daily.log"
mkdir -p "$updates" "$logs"

notify() {  # SUBJECT BODY
  if [ -z "${ALERT_TO:-}" ]; then echo "ALERT_TO is not set; cannot send e-mail: $1" >> "$log"; return; fi
  if command -v msmtp >/dev/null; then
    printf 'To: %s\nSubject: %s\n\n%s\n' "$ALERT_TO" "$1" "$2" | msmtp "$ALERT_TO" || echo "msmtp failed" >> "$log"
  elif command -v mail >/dev/null; then
    printf '%s\n' "$2" | mail -s "$1" "$ALERT_TO" || echo "mail failed" >> "$log"
  else
    echo "no msmtp/mail command; cannot send e-mail: $1" >> "$log"
  fi
}

# One run at a time (mkdir is atomic); a lock older than 3 hours is treated as stale.
lock="$root/.daily.lock"
if ! mkdir "$lock" 2>/dev/null; then
  if [ -n "$(find "$lock" -maxdepth 0 -mmin +180 2>/dev/null)" ]; then
    rmdir "$lock" 2>/dev/null; mkdir "$lock" 2>/dev/null || exit 0
  else
    echo "$(date -u +%FT%TZ) another run is in progress, skipping" >> "$log"; exit 0
  fi
fi
out=$(mktemp)
trap 'rmdir "$lock" 2>/dev/null; rm -f "$out"' EXIT

"$(dirname "$0")/fetch_tw_daily.sh" --snapshot "$updates" > "$out" 2>&1
rc=$?
{ echo "== $(date -u +%FT%TZ) exit $rc"; cat "$out"; } >> "$log"
find "$updates" -name '????-??-??.csv' -mtime +"$keep_days" -delete
tail -n 3000 "$log" > "$log.tmp" && mv "$log.tmp" "$log"      # keep the log small

if [ $rc -ne 0 ]; then
  notify "stock daily update FAILED on $(hostname) ($(date -u +%F))" "$(tail -n 40 "$out")"
  exit $rc
fi
if grep -qE '^(new|updated):' "$out"; then
  echo "  -> new data written" >> "$log"
else
  echo "  -> no new trading day" >> "$log"
  # A long silence (beyond the longest market holiday) means the exchange feed has probably changed.
  if ! find "$updates" -name '????-??-??.csv' -mtime -10 2>/dev/null | grep -q .; then
    notify "stock daily update: no new data for 10 days on $(hostname)" "No snapshot file has changed in $updates for 10 days.
Last log lines:
$(tail -n 20 "$log")"
  fi
fi