File: timer.sh

package info (click to toggle)
shepherd 1.0.9-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,828 kB
  • sloc: lisp: 8,779; sh: 3,586; makefile: 289; ansic: 50
file content (211 lines) | stat: -rw-r--r-- 8,521 bytes parent folder | download
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# GNU Shepherd --- Test timed services.
# Copyright © 2024-2025 Ludovic Courtès <ludo@gnu.org>
#
# This file is part of the GNU Shepherd.
#
# The GNU Shepherd is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at
# your option) any later version.
#
# The GNU Shepherd is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the GNU Shepherd.  If not, see <https://www.gnu.org/licenses/>.

shepherd --version
herd --version

socket="t-socket-$$"
conf="t-conf-$$"
log="t-log-$$"
pid="t-pid-$$"
service_pid="t-service-pid-$$"
service_child_pid="t-service-child-pid-$$"
service_log="t-service-log-$$"

herd="herd -s $socket"

trap "cat $log || true; rm -f $socket $conf $log $service_pid $service_child_pid $service_log;
      test -f $pid && kill \`cat $pid\` || true; rm -f $pid" EXIT

cat > "$conf" <<EOF
(use-modules (shepherd service timer) (srfi srfi-19))

(define endless
  "echo Started endless timer.; echo \$\$ > $PWD/$service_pid; sleep 500 & \
echo \$! > $PWD/$service_child_pid; wait")

(define timers
  (list (service '(timer-with-command)
		 #:start (make-timer-constructor
			  (calendar-event #:seconds (iota 60))
			  (command '("sh" "-c" "echo Hi from \$PWD."))
                          #:log-file "$service_log")
		 #:stop (make-timer-destructor))
        (service '(timer-with-procedure)
                 #:start (make-timer-constructor
			  (calendar-event #:seconds (iota 60))
                          (lambda () (display "Hello from procedure.\n")))
                 #:stop (make-timer-destructor))
        (service '(timer-that-throws)
                 #:start (make-timer-constructor
			  (calendar-event #:seconds (iota 60))
                          (lambda () (display "Throwing!\n") (mkdir "/")))
                 #:stop (make-timer-destructor)
	         #:actions (list timer-trigger-action))
        (service '(endless-timer)
                 #:start (make-timer-constructor
                          (calendar-event #:seconds (iota 60))
                          (command (quasiquote ("sh" "-c" ,endless)))
                          #:wait-for-termination? #t)
                 #:stop (make-timer-destructor))
        (service '(timer-that-takes-too-long)
                 #:start (make-timer-constructor
                          (calendar-event
                            #:months
                            (if (<= (date-month (current-date)) 6)
                                '(12)
                                '(1)))
                          (command (quote ("sh" "-c" "echo Sleeping.; exec sleep 100")))
                          #:max-duration 1)
                 #:stop (make-timer-destructor)
                 #:actions (list timer-trigger-action))
        (service '(timer-that-resists)   ;ignores SIGTERM
                 #:start (make-timer-constructor
                          (calendar-event
                            #:months
                            (if (<= (date-month (current-date)) 6)
                                '(12)
                                '(1)))
                          (command (quote ("sh" "-c"
                                           "trap 'echo \$\$ eats SIGTERM' TERM; while true; do sleep 1; done")))
                          #:max-duration 1)
                 #:stop (make-timer-destructor)
                 #:actions (list timer-trigger-action))
        (service '(timer-with-two-occurrences)
                 #:start (make-timer-constructor
                          (calendar-event #:seconds (iota 60))
                          (lambda () (display "limited number of occurrences\n"))
                          #:occurrences 2)
                 #:stop (make-timer-destructor))
        (service '(timer-without-matching-events)
                 #:start (make-timer-constructor
                          (calendar-event #:seconds '())  ;broken event!
                          (lambda () (display "What?!\n")))
                 #:stop (make-timer-destructor))
        (service '(never-timer)
                 #:start (make-timer-constructor
                          (calendar-event
                            #:months
                            (if (<= (date-month (current-date)) 6)
                                '(12)
                                '(1)))
                          (command (quote ("sh" "-c" "echo Triggered from \$PWD."))
                                   #:directory "$PWD"))
                 #:stop (make-timer-destructor)
                 #:actions (list timer-trigger-action))))

(register-services timers)
EOF

rm -f "$pid"
shepherd -I -s "$socket" -c "$conf" -l "$log" --pid="$pid" &

# Wait till it's ready.
while ! test -f "$pid" ; do sleep 0.3 ; done

shepherd_pid="`cat $pid`"

$herd start timer-with-command
sleep 2
grep "Hi from " "$service_log"
$herd status timer-with-command | grep "Log file: $PWD/$service_log"
$herd status timer-with-command | grep "Hi from " # recent messages
$herd status timer-with-command | grep "exited successfully" # recent runs
$herd stop timer-with-command

$herd start timer-with-procedure
sleep 2
$herd status timer-with-procedure | grep "Completed in" # recent runs
grep "Hello from procedure" "$log"

$herd start timer-that-throws
$herd trigger timer-that-throws
until grep "Throwing" "$log"; do sleep 0.3; done
$herd status timer-that-throws | grep "Exception thrown.*mkdir" # recent runs

rm -f "$service_pid"
$herd start endless-timer
sleep 2
grep "Started endless timer" "$log"
$herd status endless-timer | grep "Started endless timer" # recent messages
kill -0 $(cat "$service_pid")
until kill -0 $(cat "$service_child_pid"); do sleep 0.2; done
$herd status endless-timer | grep "Executing timer action"
$herd status endless-timer | grep "Child process: $(cat "$service_pid")"
$herd stop endless-timer
kill -0 $(cat "$service_pid") && false	     # Main process and its entire
kill -0 $(cat "$service_child_pid") && false # process group must be stopped.
grep "Process $(cat "$service_pid") of timer 'endless-timer' terminated" "$log"

$herd start timer-that-takes-too-long
for i in $(seq 3)
do
    $herd trigger timer-that-takes-too-long
    # Check "recent messages" and "recent runs" in the output of 'herd status'.
    until $herd status timer-that-takes-too-long | \
	    grep "[0-9][0-9]:[0-9][0-9] Sleeping"; do sleep 0.3; done
    until test $($herd status timer-that-takes-too-long | \
	    grep "terminated with signal 15" | wc -l) -eq $i; do sleep 0.3; done
    if $herd status timer-that-takes-too-long | grep "Child process"
    then false; else true; fi
    test $(grep "Terminating.*timer-that-takes-too-long.*after maximum duration" "$log" | wc -l) \
	 -eq $i
done

# Start several timer processes, all of which exceed #:max-duration and
# ignore SIGTERM.  They should eventually get SIGKILL just fine.
# See <https://codeberg.org/shepherd/shepherd/issues/2>.
$herd start timer-that-resists
for i in $(seq 1 10)
do
    $herd trigger timer-that-resists
done
until test $(grep "Terminating.*timer-that-resists.*after maximum duration" "$log" | wc -l) \
	  -eq $i; do sleep 0.3; done
until test $($herd status timer-that-resists -n 20 | \
		 grep "terminated with signal 9" | wc -l) -eq $i; do sleep 0.3; done
if $herd status timer-that-resists | grep "Child process"
then false; else true; fi

$herd start timer-with-two-occurrences
until $herd status timer-with-two-occurrences | grep stopped; do sleep 0.3; done
test $(grep "limited number of occurrences" "$log" | wc -l) -eq 2

$herd start timer-without-matching-events && false
$herd status timer-without-matching-events | grep "stopped.*failing"

$herd start never-timer
grep "Triggered from $PWD" "$log" && false
$herd trigger never-timer
until grep "Triggered from $PWD" "$log"; do sleep 0.3; done

$herd stop root

while kill -0 "$(cat $pid)" ; do sleep 0.2; done

# Check error reports when config is invalid.
cat > "$conf" <<EOF
(use-modules (shepherd service timer))

(calendar-event #:days-of-week '(1 2 3))  ;wrong!
EOF
rm -f "$pid"
shepherd -I -s "$socket" -c "$conf" -l "$log" --pid="$pid" &
until grep "invalid day of week" "$log"; do sleep 0.2; done

$herd stop root