xref: /aosp_15_r20/external/rappor/pipeline/alarm-lib.sh (revision 2abb31345f6c95944768b5222a9a5ed3fc68cc00)
1#!/bin/bash
2#
3# Alarm tool.
4#
5# Usage:
6#   ./alarm.sh <function name>
7
8# You can source this file and use the alarm-status function.
9
10set -o nounset
11set -o pipefail
12set -o errexit
13
14# Run a command with a timeout, and print its status to a directory.
15#
16# Usage:
17#   alarm-status job_dir/STATUS 10 \
18#     flaky_command ...
19
20alarm-status() {
21  set +o errexit
22  local status_file=$1
23  shift  # everything except the status file goes to perl
24
25  # NOTE: It would be nice to setpgrp() before exec?  And then can the signal
26  # be delivered to the entire group, like kill -SIGALRM -PID?
27
28  # NOTE: If we did this in Python, the error message would also be clearer.
29  perl -e 'alarm shift; exec @ARGV or die "ERROR: after exec @ARGV"' "$@"
30  local exit_code=$?
31
32  set -o errexit
33
34  local result=''
35  case $exit_code in
36    0)
37      # Would be nice to show elapsed time?
38      result='OK'
39      ;;
40    9)
41      # decode_assoc.R will exit 9 if there are no reports AFTER
42      # --remove-bad-rows.  A task can also be marked SKIPPED before running
43      # the child process (see backfill.sh).
44      result='SKIPPED by child process'
45      ;;
46    # exit code 142 means SIGALARM.  128 + 14 = 142.  See 'kill -l'.
47    142)
48      local seconds=$1
49      result="TIMEOUT after $seconds seconds"
50      ;;
51    *)
52      result="FAIL with status $exit_code"
53      ;;
54  esac
55  echo "$result"
56  echo "$result" > $status_file
57}
58
59_work() {
60  local n=10  # 2 seconds
61  for i in $(seq $n); do
62    echo $i - "$@"
63    sleep 0.2
64  done
65}
66
67_succeed() {
68  _work "$@"
69  exit 0
70}
71
72_fail() {
73  _work "$@"
74  exit 1
75}
76
77_skip() {
78  exit 9
79}
80
81# http://perldoc.perl.org/functions/alarm.html
82#
83# Delivers alarm.  But how to get the process to have a distinct exit code?
84
85demo() {
86  mkdir -p _tmp
87
88  # timeout
89  alarm-status _tmp/A 1 $0 _succeed foo
90  echo
91
92  # ok
93  alarm-status _tmp/B 3 $0 _succeed bar
94  echo
95
96  # fail
97  alarm-status _tmp/C 3 $0 _fail baz
98  echo
99
100  # skip
101  alarm-status _tmp/D 3 $0 _skip baz
102  echo
103
104  head _tmp/{A,B,C,D}
105}
106
107test-simple() {
108  alarm-status _tmp/status.txt 1 sleep 2
109}
110
111test-bad-command() {
112  alarm-status _tmp/status.txt 1 nonexistent_sleep 2
113}
114
115# BUG
116test-perl() {
117  set +o errexit
118  perl -e 'alarm shift; exec @ARGV or die "ERROR after exec @ARGV"' 1 _sleep 2
119  echo $?
120}
121
122if test $(basename $0) = 'alarm-lib.sh'; then
123  "$@"
124fi
125