feat: check subcommand for firing off expired alarms
This commit is contained in:
parent
9de60f23cc
commit
c6b2148eea
2 changed files with 164 additions and 12 deletions
85
nag
85
nag
|
|
@ -651,20 +651,20 @@ _next_for_rule() {
|
|||
_time_of_day="$(date -d "@${_timestamp}" +%H:%M:%S)"
|
||||
|
||||
case "${_rule}" in
|
||||
hourly) printf "%s" "$((_timestamp + 3600))" ;;
|
||||
daily) date -d "$(date -d "@${_timestamp}" +%Y-%m-%d) + 1 day ${_time_of_day}" +%s ;;
|
||||
weekly) _next_matching_day "${_timestamp}" "${_time_of_day}" "$(date -d "@${_timestamp}" +%u)" ;;
|
||||
hour) printf "%s" "$((_timestamp + 3600))" ;;
|
||||
day) date -d "$(date -d "@${_timestamp}" +%Y-%m-%d) + 1 day ${_time_of_day}" +%s ;;
|
||||
week) _next_matching_day "${_timestamp}" "${_time_of_day}" "$(date -d "@${_timestamp}" +%u)" ;;
|
||||
weekday) _next_matching_day "${_timestamp}" "${_time_of_day}" "1 2 3 4 5" ;;
|
||||
weekend) _next_matching_day "${_timestamp}" "${_time_of_day}" "6 7" ;;
|
||||
mon) _next_matching_day "${_timestamp}" "${_time_of_day}" "1" ;;
|
||||
tue) _next_matching_day "${_timestamp}" "${_time_of_day}" "2" ;;
|
||||
wed) _next_matching_day "${_timestamp}" "${_time_of_day}" "3" ;;
|
||||
thu) _next_matching_day "${_timestamp}" "${_time_of_day}" "4" ;;
|
||||
fri) _next_matching_day "${_timestamp}" "${_time_of_day}" "5" ;;
|
||||
sat) _next_matching_day "${_timestamp}" "${_time_of_day}" "6" ;;
|
||||
sun) _next_matching_day "${_timestamp}" "${_time_of_day}" "7" ;;
|
||||
monthly) _next_month "${_timestamp}" "${_time_of_day}" ;;
|
||||
yearly) _next_year "${_timestamp}" "${_time_of_day}" ;;
|
||||
mon) _next_matching_day "${_timestamp}" "${_time_of_day}" "1" ;;
|
||||
tue) _next_matching_day "${_timestamp}" "${_time_of_day}" "2" ;;
|
||||
wed) _next_matching_day "${_timestamp}" "${_time_of_day}" "3" ;;
|
||||
thu) _next_matching_day "${_timestamp}" "${_time_of_day}" "4" ;;
|
||||
fri) _next_matching_day "${_timestamp}" "${_time_of_day}" "5" ;;
|
||||
sat) _next_matching_day "${_timestamp}" "${_time_of_day}" "6" ;;
|
||||
sun) _next_matching_day "${_timestamp}" "${_time_of_day}" "7" ;;
|
||||
month) _next_month "${_timestamp}" "${_time_of_day}" ;;
|
||||
year) _next_year "${_timestamp}" "${_time_of_day}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
|
@ -1072,6 +1072,67 @@ stop() {
|
|||
printf "Stopped alarm %s.\\n" "${_target_id}"
|
||||
}
|
||||
|
||||
# check #######################################################################
|
||||
|
||||
describe "check" <<HEREDOC
|
||||
Usage:
|
||||
${_ME} check
|
||||
|
||||
Description:
|
||||
Fire expired alarms. Intended to be run by cron every minute.
|
||||
Repeating alarms are rescheduled. One-shot alarms are removed.
|
||||
HEREDOC
|
||||
check() {
|
||||
[[ -f "${_ALARMS_FILE}" ]] || return 0
|
||||
|
||||
_acquire_lock
|
||||
_read_alarms
|
||||
|
||||
local -a _new_alarms=()
|
||||
local _now
|
||||
_now="$(date +%s)"
|
||||
local _line
|
||||
|
||||
for _line in "${_ALARMS[@]:-}"
|
||||
do
|
||||
[[ -n "${_line}" ]] || continue
|
||||
|
||||
local _id _timestamp _rule _message
|
||||
_id="$(_get_alarm_field "${_line}" 1)"
|
||||
_timestamp="$(_get_alarm_field "${_line}" 2)"
|
||||
_rule="$(_get_alarm_field "${_line}" 3)"
|
||||
_message="$(_get_alarm_field "${_line}" 4)"
|
||||
|
||||
if (( _timestamp <= _now ))
|
||||
then
|
||||
# Fire it.
|
||||
${NAG_CMD} "nag" "${_message}" || _warn printf "Failed to notify: %s\\n" "${_message}"
|
||||
|
||||
if [[ -n "${_rule}" ]]
|
||||
then
|
||||
# Repeating: reschedule.
|
||||
local _next_ts
|
||||
_next_ts="$(_next_occurrence "${_rule}" "${_timestamp}")"
|
||||
_new_alarms+=("$(printf "%s\t%s\t%s\t%s" "${_id}" "${_next_ts}" "${_rule}" "${_message}")")
|
||||
fi
|
||||
# One-shot: drop it (don't add to _new_alarms).
|
||||
else
|
||||
# Not expired — keep it.
|
||||
_new_alarms+=("${_line}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${#_new_alarms[@]}" -eq 0 ]]
|
||||
then
|
||||
_ALARMS=()
|
||||
: > "${_ALARMS_FILE}"
|
||||
else
|
||||
_ALARMS=("${_new_alarms[@]}")
|
||||
_write_alarms
|
||||
fi
|
||||
_release_lock
|
||||
}
|
||||
|
||||
# at ##########################################################################
|
||||
|
||||
describe "at" <<HEREDOC
|
||||
|
|
|
|||
|
|
@ -213,3 +213,94 @@ load test_helper
|
|||
[[ "${_first_line}" =~ "standup" ]]
|
||||
[[ "${_second_line}" =~ "take a break" ]]
|
||||
}
|
||||
|
||||
# check #######################################################################
|
||||
|
||||
# Helper: write a raw alarm line directly to the alarms file.
|
||||
write_alarm() {
|
||||
mkdir -p "${NAG_DIR}"
|
||||
printf "%s\\n" "$1" >> "${NAG_DIR}/alarms"
|
||||
}
|
||||
|
||||
@test "check fires expired one-shot and removes it" {
|
||||
local _past_ts=$(( $(date +%s) - 60 ))
|
||||
write_alarm "$(printf "1\t%s\t\tpast alarm" "${_past_ts}")"
|
||||
|
||||
# Record what was fired.
|
||||
local _fired="${NAG_DIR}/fired"
|
||||
export NAG_CMD="${NAG_DIR}/recorder"
|
||||
cat > "${NAG_CMD}" <<'SCRIPT'
|
||||
#!/usr/bin/env bash
|
||||
printf "%s\n" "$2" >> "${NAG_DIR}/fired"
|
||||
SCRIPT
|
||||
chmod +x "${NAG_CMD}"
|
||||
|
||||
run "${_NAG}" check
|
||||
[ "${status}" -eq 0 ]
|
||||
|
||||
# Alarm should have been removed.
|
||||
[[ ! -s "${NAG_DIR}/alarms" ]] || [ "$(wc -l < "${NAG_DIR}/alarms")" -eq 0 ]
|
||||
|
||||
# Notification should have fired.
|
||||
grep -q "past alarm" "${_fired}"
|
||||
}
|
||||
|
||||
@test "check reschedules expired repeating alarm" {
|
||||
local _past_ts=$(( $(date +%s) - 60 ))
|
||||
write_alarm "$(printf "1\t%s\tday\tdaily alarm" "${_past_ts}")"
|
||||
|
||||
run "${_NAG}" check
|
||||
[ "${status}" -eq 0 ]
|
||||
|
||||
# Alarm should still exist with a future timestamp.
|
||||
[ -s "${NAG_DIR}/alarms" ]
|
||||
local _new_ts
|
||||
_new_ts="$(cut -f2 "${NAG_DIR}/alarms" | head -1)"
|
||||
local _now
|
||||
_now="$(date +%s)"
|
||||
(( _new_ts > _now ))
|
||||
}
|
||||
|
||||
@test "check does not fire future alarms" {
|
||||
local _future_ts=$(( $(date +%s) + 3600 ))
|
||||
write_alarm "$(printf "1\t%s\t\tfuture alarm" "${_future_ts}")"
|
||||
|
||||
run "${_NAG}" check
|
||||
[ "${status}" -eq 0 ]
|
||||
|
||||
# Alarm should still be there, unchanged.
|
||||
[ -s "${NAG_DIR}/alarms" ]
|
||||
grep -q "future alarm" "${NAG_DIR}/alarms"
|
||||
}
|
||||
|
||||
@test "check fires all missed alarms" {
|
||||
local _past1=$(( $(date +%s) - 120 ))
|
||||
local _past2=$(( $(date +%s) - 60 ))
|
||||
write_alarm "$(printf "1\t%s\t\tmissed one" "${_past1}")"
|
||||
write_alarm "$(printf "2\t%s\t\tmissed two" "${_past2}")"
|
||||
|
||||
local _fired="${NAG_DIR}/fired"
|
||||
export NAG_CMD="${NAG_DIR}/recorder"
|
||||
cat > "${NAG_CMD}" <<'SCRIPT'
|
||||
#!/usr/bin/env bash
|
||||
printf "%s\n" "$2" >> "${NAG_DIR}/fired"
|
||||
SCRIPT
|
||||
chmod +x "${NAG_CMD}"
|
||||
|
||||
run "${_NAG}" check
|
||||
[ "${status}" -eq 0 ]
|
||||
|
||||
# Both should have fired.
|
||||
grep -q "missed one" "${_fired}"
|
||||
grep -q "missed two" "${_fired}"
|
||||
|
||||
# Both should be removed (one-shots).
|
||||
[[ ! -s "${NAG_DIR}/alarms" ]] || [ "$(wc -l < "${NAG_DIR}/alarms")" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "help check shows check usage" {
|
||||
run "${_NAG}" help check
|
||||
[ "${status}" -eq 0 ]
|
||||
[[ "${output}" =~ "Usage:" ]]
|
||||
[[ "${output}" =~ "check" ]]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue