Add the scheduling module
Three replicas of one application against one PostgreSQL database, proving duplicate @Scheduled execution and then removing it with ShedLock: 24 executions where 8 were due, then 7 for 7 ticks. Also measured: @SchedulerLock without @EnableSchedulerLock does nothing and warns about nothing; spring.task.scheduling.pool.size=1 does not starve a fixedRate job but delays it and fires 35 of 40 executions in a burst; and a node whose clock is 40 seconds fast takes a live lock unless the provider uses usingDbTime().
This commit is contained in:
52
scheduling/scripts/three-replicas.sh
Executable file
52
scheduling/scripts/three-replicas.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# Starts three replicas of the application against one database, lets the schedule tick, and
|
||||
# tallies who ran the job.
|
||||
#
|
||||
# scripts/three-replicas.sh unlocked # no @EnableSchedulerLock: every replica runs it
|
||||
# scripts/three-replicas.sh locked # ShedLock with usingDbTime()
|
||||
# scripts/three-replicas.sh appclock 40 # ShedLock without usingDbTime(), replica-3 40s fast
|
||||
#
|
||||
# Environment:
|
||||
# RUN_FOR seconds to let the schedule tick (default 30; three JVMs need ~10s to start)
|
||||
# JOB_DURATION ISO-8601 duration the job sleeps for (default PT0.2S)
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
PROFILE="${1:-unlocked}"
|
||||
SKEW_SECONDS="${2:-0}"
|
||||
RUN_FOR="${RUN_FOR:-30}"
|
||||
JOB_DURATION="${JOB_DURATION:-PT0.2S}"
|
||||
JAR=target/scheduling-1.0.jar
|
||||
PSQL=(scripts/postgres.sh psql)
|
||||
|
||||
[ -f "$JAR" ] || mvn -B -q -DskipTests package
|
||||
|
||||
"${PSQL[@]}" -q -c "delete from job_execution" -c "delete from shedlock" >/dev/null 2>&1 || true
|
||||
|
||||
pids=()
|
||||
for n in 1 2 3; do
|
||||
skew=()
|
||||
if [ "$SKEW_SECONDS" != "0" ] && [ "$n" = "3" ]; then
|
||||
skew=(-Dclock.skew="PT${SKEW_SECONDS}S")
|
||||
fi
|
||||
java -Dspring.profiles.active="$PROFILE" -DINSTANCE_ID="replica-$n" \
|
||||
-Djob.duration="$JOB_DURATION" "${skew[@]}" \
|
||||
-jar "$JAR" > "target/replica-$n.log" 2>&1 &
|
||||
pids+=($!)
|
||||
done
|
||||
|
||||
sleep "$RUN_FOR"
|
||||
for p in "${pids[@]}"; do kill "$p" 2>/dev/null || true; done
|
||||
wait 2>/dev/null || true
|
||||
|
||||
echo "profile=$PROFILE replicas=3 run-for=${RUN_FOR}s job rate=3s job duration=$JOB_DURATION replica-3 clock skew=${SKEW_SECONDS}s"
|
||||
echo
|
||||
echo "-- every execution, in order --"
|
||||
"${PSQL[@]}" -c "select instance_id, to_char(started_at,'HH24:MI:SS.MS') as started_at from job_execution order by started_at"
|
||||
echo "-- executions per replica --"
|
||||
"${PSQL[@]}" -c "select instance_id, count(*) from job_execution group by instance_id order by instance_id"
|
||||
OVERLAP="b.id > a.id and b.instance_id <> a.instance_id and b.started_at < a.started_at + interval '$JOB_DURATION'"
|
||||
echo "-- pairs of executions that overlapped (a second replica started while the first was still working) --"
|
||||
"${PSQL[@]}" -c "select count(*) as overlapping_pairs from job_execution a join job_execution b on $OVERLAP"
|
||||
"${PSQL[@]}" -c "select a.instance_id as first, to_char(a.started_at, 'HH24:MI:SS.MS') as first_at, b.instance_id as second, to_char(b.started_at, 'HH24:MI:SS.MS') as second_at from job_execution a join job_execution b on $OVERLAP order by a.started_at limit 6"
|
||||
echo "-- the lock row --"
|
||||
"${PSQL[@]}" -c "select name, locked_by, to_char(locked_at,'HH24:MI:SS.MS') as locked_at, to_char(lock_until,'HH24:MI:SS.MS') as lock_until from shedlock"
|
||||
Reference in New Issue
Block a user