Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan
Reka bentuk operasi yang selamat untuk dijalankan semula dan tambahkan penangguhan eksponen bagi panggilan luaran yang tidak stabil
Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan ialah pelajaran Penguasaan Baris Perintah Linux & Penskripan Bash percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Penguasaan Baris Perintah Linux & Penskripan Bash, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Penguasaan Baris Perintah Linux & Penskripan Bash merangkumi sejumlah 4 pelajaran.
Apakah Idempotenan dan Mengapa Ia Penting
Idempotenan bermaksud menjalankan operasi yang sama beberapa kali menghasilkan keputusan yang sama seperti menjalankannya sekali. Dalam penskripan Bash, perkara ini penting kerana skrip boleh ranap, rangkaian boleh terputus dan manusia boleh menjalankan semula sesuatu secara tidak sengaja.
- Skrip yang tidak idempoten dan mencipta pengguna dua kali mungkin gagal atau menghasilkan data pendua.
- Skrip idempoten membuat pemeriksaan dahulu: adakah perkara ini sudah wujud?
- Skrip idempoten selamat digunakan dalam tugas cron, saluran paip CI dan gelung percubaan semula.
Peraturan emas: buat pemeriksaan sebelum bertindak. Setiap operasi yang memusnahkan atau mencipta sesuatu hendaklah dilindungi oleh ujian prasyarat.
Melindungi Penciptaan File dan Direktori
Corak idempotenan yang paling biasa ialah memeriksa sama ada sumber sudah wujud sebelum menciptanya. Bash menyediakan arahan satu baris yang ringkas untuk tujuan ini.
[ -d dir ]— benar jika direktori wujud[ -f file ]— benar jika file biasa wujudmkdir -p— mencipta direktori hanya jika tiada (idempotenan terbina dalam)
Utamakan bendera terbina dalam seperti -p dan --no-clobber berbanding pemeriksaan manual apabila tersedia — bendera ini bersifat atom dan selamat daripada keadaan perlumbaan.
#!/usr/bin/env bash
set -euo pipefail
CONFIG_DIR="$HOME/.myapp"
CONFIG_FILE="$CONFIG_DIR/config.ini"
# Idempotent: mkdir -p never fails if dir already exists
mkdir -p "$CONFIG_DIR"
# Idempotent: only write config if it doesn't exist yet
if [ ! -f "$CONFIG_FILE" ]; then
echo '[defaults]' > "$CONFIG_FILE"
echo 'timeout=30' >> "$CONFIG_FILE"
echo "Created $CONFIG_FILE"
else
echo "Config already exists, skipping."
fiPengurusan Pengguna dan Kumpulan Idempoten
Tugas pentadbiran sistem seperti menambah pengguna atau kumpulan mestilah idempoten — menjalankan semula skrip pada mesin yang sama tidak sepatutnya menghasilkan ralat atau pendua.
id usernamemengembalikan 0 jika pengguna wujudgetent group groupnamememeriksa kewujudan kumpulan- Bungkus setiap operasi dalam perlindungan supaya skrip selamat untuk dijalankan semula
Corak ini menjadi asas alat pengurusan konfigurasi seperti Ansible — setiap tugas ialah operasi yang dilindungi dan idempoten.
#!/usr/bin/env bash
set -euo pipefail
APP_USER="apprunner"
APP_GROUP="appgroup"
# Idempotent group creation
if ! getent group "$APP_GROUP" &>/dev/null; then
groupadd "$APP_GROUP"
echo "Group '$APP_GROUP' created."
else
echo "Group '$APP_GROUP' already exists."
fi
# Idempotent user creation
if ! id "$APP_USER" &>/dev/null; then
useradd -m -g "$APP_GROUP" -s /bin/bash "$APP_USER"
echo "User '$APP_USER' created."
else
echo "User '$APP_USER' already exists."
fiMenggunakan File Kunci untuk Menghalang Pelaksanaan Serentak
Malah skrip idempoten boleh menyebabkan masalah jika dua tika berjalan serentak. File kunci memastikan hanya satu tika berjalan pada satu-satu masa.
- Cipta file kunci semasa permulaan; buangnya semasa keluar.
- Gunakan
trapuntuk membersihkan kunci walaupun skrip terganggu. mkdirpada satu laluan bersifat atom pada kebanyakan sistem file Linux — lebih selamat daripadatouchuntuk penguncian.
Tanpa kunci, tugas cron yang perlahan dan pelaksanaan semula secara manual boleh bertembung lalu merosakkan keadaan dikongsi.
#!/usr/bin/env bash
set -euo pipefail
LOCKFILE="/tmp/myapp_deploy.lock"
# Atomic lock acquisition using mkdir
if ! mkdir "$LOCKFILE" 2>/dev/null; then
echo "ERROR: Another instance is running (lock: $LOCKFILE). Exiting." >&2
exit 1
fi
# Guarantee lock removal on any exit
trap 'rmdir "$LOCKFILE"; echo "Lock released."' EXIT
echo "Lock acquired. Running deployment..."
sleep 2 # simulate work
echo "Deployment complete."Menjejaki Langkah yang Selesai dengan File Keadaan
Untuk skrip berbilang langkah (pemindahan, pemasangan, penyediaan), Anda boleh menjejaki langkah yang telah selesai menggunakan file keadaan. Setiap langkah memeriksa file keadaan sebelum dilaksanakan dan menulis kepadanya selepas selesai.
- Murah dan mudah alih — tiada pangkalan data diperlukan.
- Membolehkan skrip yang gagal menyambung semula dari tempat ia berhenti.
- Simpan keadaan di lokasi yang boleh diramal seperti
/var/lib/myapp/atau~/.myapp/state/.
Corak ini digunakan oleh alat utama seperti apt, cloud-init dan rangka kerja pemindahan pangkalan data.
#!/usr/bin/env bash
set -euo pipefail
STATE_DIR="/tmp/myapp_state"
mkdir -p "$STATE_DIR"
run_step() {
local step_name="$1"
local step_cmd="$2"
local marker="$STATE_DIR/${step_name}.done"
if [ -f "$marker" ]; then
echo "[SKIP] $step_name already completed."
return 0
fi
echo "[RUN] $step_name ..."
eval "$step_cmd"
touch "$marker"
echo "[DONE] $step_name"
}
run_step "install_deps" "echo 'Installing dependencies...'"
run_step "configure_db" "echo 'Configuring database...'"
run_step "start_service" "echo 'Starting service...'"Pengenalan kepada Logik Percubaan Semula
Panggilan luaran — permintaan HTTP, carian DNS dan panggilan API awan — sememangnya tidak boleh dipercayai. Satu kegagalan tidak sepatutnya menghentikan keseluruhan skrip Anda. Logik percubaan semula mencuba semula arahan yang gagal secara automatik.
- Percubaan semula naif: ulang gelung sebanyak N kali sehingga arahan berjaya.
- Sentiasa tetapkan bilangan maksimum percubaan semula untuk mengelakkan gelung tanpa penghujung.
- Catat setiap percubaan supaya kegagalan boleh didiagnosis.
Fungsi percubaan semula paling ringkas membungkus sebarang arahan dan mencubanya semula sehingga bilangan tetap dengan kelewatan malar. Ini memadai untuk banyak kegunaan, tetapi mempunyai kelemahan kritikal apabila beban tinggi — seperti yang diterangkan seterusnya.
#!/usr/bin/env bash
set -euo pipefail
# Simple fixed-delay retry (3 attempts, 2s apart)
retry() {
local max_attempts=3
local delay=2
local attempt=1
until "$@"; do
if (( attempt >= max_attempts )); then
echo "ERROR: Command failed after $max_attempts attempts: $*" >&2
return 1
fi
echo "Attempt $attempt failed. Retrying in ${delay}s..." >&2
sleep "$delay"
(( attempt++ ))
done
}
# Example: retry a curl call
retry curl --silent --fail --max-time 5 https://httpbin.org/get -o /dev/null
echo "Request succeeded."Masalah Gerombolan Mengamuk
Apabila banyak klien mencuba semula secara serentak selepas kegagalan, mereka menghasilkan gerombolan mengamuk — semuanya mencuba semula pada selang tetap yang sama, membebankan pelayan tepat pada saat yang sama dan menjadikan pemulihan mustahil.
- 100 skrip mencuba semula setiap 5 saat → 100 permintaan serentak setiap 5 saat.
- Pelayan memang sudah bergelut; beban yang disegerakkan menjadikannya lebih teruk.
- Penyelesaiannya ialah undur eksponen: gandakan tempoh menunggu selepas setiap kegagalan.
- Tambahkan jitter (gangguan rawak) untuk menyahsegerakkan percubaan semula merentas klien.
Undur eksponen dengan jitter ialah piawaian industri yang digunakan oleh SDK AWS, klien Google Cloud dan setiap sistem teragih utama.
Melaksanakan Penangguhan Eksponen
Penangguhan eksponen meningkatkan masa menunggu secara eksponen selepas setiap kegagalan: 1s, 2s, 4s, 8s, 16s... Ini memberikan masa kepada sistem jauh untuk pulih sambil mengurangkan beban keseluruhan.
Formulanya: delay = base * (2 ^ attempt)
- Tetapkan had (kelewatan maksimum) supaya masa menunggu tidak meningkat tanpa batas.
- Parameter untuk dilaraskan:
base_delay,max_delay,max_attempts.
Fungsi ini boleh digunakan semula — hantarkan apa-apa perintah kepadanya sebagai argumen.
#!/usr/bin/env bash
set -euo pipefail
retry_with_backoff() {
local max_attempts="${RETRY_MAX_ATTEMPTS:-5}"
local base_delay="${RETRY_BASE_DELAY:-1}"
local max_delay="${RETRY_MAX_DELAY:-30}"
local attempt=0
local delay="$base_delay"
until "$@"; do
(( attempt++ ))
if (( attempt >= max_attempts )); then
echo "ERROR: '$*' failed after $max_attempts attempts." >&2
return 1
fi
echo "Attempt $attempt failed. Backing off for ${delay}s..." >&2
sleep "$delay"
# Double the delay, but cap it
delay=$(( delay * 2 ))
(( delay > max_delay )) && delay=$max_delay
done
echo "Command succeeded on attempt $(( attempt + 1 ))."
}
retry_with_backoff echo "Simulated success"Menambahkan Jiter pada Penangguhan
Jiter menambahkan kerawakan pada kelewatan penangguhan. Walaupun menggunakan penangguhan eksponen, jika semua klien bermula pada masa yang sama, mereka masih akan mencuba semula secara serentak. Jiter memecahkan penyegerakan ini.
Dua strategi jiter yang biasa:
- Jiter penuh:
sleep random(0, cap)— penyebaran maksimum, beban puncak paling rendah. - Jiter sama rata:
sleep cap/2 + random(0, cap/2)— menjamin masa menunggu minimum dan mengelakkan percubaan bertalu-talu dengan serta-merta.
Dalam Bash, gunakan $RANDOM (0–32767) untuk menjana nombor rawak. Skalakan nombor itu kepada julat kelewatan anda menggunakan aritmetik modulo.
#!/usr/bin/env bash
set -euo pipefail
retry_with_jitter() {
local max_attempts="${1:-5}"; shift
local base_delay=1
local max_delay=32
local attempt=0
local cap=$base_delay
until "$@"; do
(( attempt++ ))
if (( attempt >= max_attempts )); then
echo "ERROR: Giving up after $max_attempts attempts." >&2
return 1
fi
# Full jitter: random value in [0, cap]
local jitter=$(( RANDOM % (cap + 1) ))
echo "Attempt $attempt failed. Sleeping ${jitter}s (cap=${cap}s)..." >&2
sleep "$jitter"
# Grow cap exponentially, bounded by max_delay
cap=$(( cap * 2 ))
(( cap > max_delay )) && cap=$max_delay
done
}
retry_with_jitter 4 curl --silent --fail --max-time 3 https://httpbin.org/get -o /dev/null
echo "Done."Menggabungkan Idempoten dan Percubaan Semula dalam Aliran Kerja Sebenar
Dalam skrip produksi, logik idempoten dan percubaan semula berfungsi bersama. Aliran kerja penggunaan biasa mungkin:
- Mendapatkan kunci (menghalang pelaksanaan serentak)
- Memeriksa fail keadaan (melangkau langkah yang telah selesai)
- Menggunakan percubaan semula dengan penangguhan untuk panggilan luaran (muat turun, API, DNS)
- Menandakan langkah sebagai selesai hanya selepas kejayaan disahkan
- Melepaskan kunci melalui
trap
Gabungan ini menjadikan skrip selamat untuk dijalankan semula pada bila-bila masa — selepas ranap, tamat masa, atau pembatalan manual — tanpa meninggalkan sistem dalam keadaan rosak.
#!/usr/bin/env bash
set -euo pipefail
STATE_DIR="/tmp/deploy_state" && mkdir -p "$STATE_DIR"
LOCK="/tmp/deploy.lock"
mkdir "$LOCK" 2>/dev/null || { echo "Already running."; exit 1; }
trap 'rmdir "$LOCK"' EXIT
step_done() { [ -f "$STATE_DIR/$1.done" ]; }
mark_done() { touch "$STATE_DIR/$1.done"; }
retry_backoff() {
local attempt=0 delay=1
until "${@:2}"; do
(( ++attempt >= $1 )) && { echo "Failed after $1 attempts."; return 1; }
echo "Retry $attempt in ${delay}s..."; sleep $delay; delay=$(( delay * 2 ))
done
}
if ! step_done "download_artifact"; then
retry_backoff 4 curl -fsSL https://httpbin.org/get -o /tmp/artifact.json
mark_done "download_artifact"
echo "[DONE] download_artifact"
else
echo "[SKIP] download_artifact"
fi
echo "Deployment finished successfully."Mengendalikan Ralat yang Tidak Boleh Dicuba Semula
Tidak semua ralat patut dicuba semula. Mencuba semula 404 Not Found atau 403 Forbidden adalah membazir — ralat tersebut tidak akan berjaya tanpa campur tangan manusia. Logik percubaan semula anda harus membezakan antara:
- Ralat sementara — tamat masa rangkaian, 503 Service Unavailable, kegagalan DNS → cuba semula
- Ralat kekal — 401 Unauthorized, 404 Not Found, input tidak sah → gagal serta-merta
Dengan curl, semak kod status HTTP dan langkau percubaan semula untuk respons 4xx. Gunakan --write-out '%{http_code}' untuk menangkap status secara berasingan daripada isi kandungan.
#!/usr/bin/env bash
set -euo pipefail
fetch_with_retry() {
local url="$1"
local max_attempts=4
local delay=1
local attempt=0
local http_code
until http_code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "$url"); do
: # curl itself failed (network error)
(( ++attempt >= max_attempts )) && { echo "Network error, giving up."; return 1; }
sleep $delay; delay=$(( delay * 2 ))
done
# Permanent client errors — do not retry
if [[ "$http_code" =~ ^4 ]]; then
echo "ERROR: HTTP $http_code for $url — not retrying." >&2
return 1
fi
# Transient server errors — retry
if [[ "$http_code" =~ ^5 ]]; then
(( ++attempt >= max_attempts )) && { echo "Server error, giving up."; return 1; }
echo "HTTP $http_code — backing off ${delay}s..."
sleep $delay; delay=$(( delay * 2 ))
fetch_with_retry "$url"
return
fi
echo "HTTP $http_code — success."
}
fetch_with_retry "https://httpbin.org/status/200"Semakan Pengetahuan: Pemilihan Strategi Penangguhan
Skrip penggunaan memuat turun artifak keluaran daripada baldi S3. Semasa insiden baru-baru ini, kesemua 80 kejadian saluran paip gagal serentak disebabkan gangguan S3 yang singkat. Apabila S3 pulih selepas 10 saat, kesemua 80 kejadian mencuba semula pada saat yang sama, lalu menyebabkan beban berlebihan sekali lagi dan memanjangkan gangguan selama 3 minit.
Strategi percubaan semula manakah yang paling baik untuk mencegah rangkaian kesan kumpulan besar ini dalam insiden akan datang?
Imbas Kembali: Idempoten dan Percubaan Semula dengan Penangguhan
Dalam pelajaran ini, anda mempelajari cara mereka bentuk skrip Bash yang selamat untuk dijalankan semula dan tahan terhadap kegagalan sementara.
Corak idempoten:
- Lindungi setiap operasi dengan pemeriksaan kewujudan (
[ -f ],[ -d ],id,getent). - Gunakan
mkdir -pdan bendera idempoten terbina dalam yang lain jika tersedia. - Gunakan fail kunci (
mkdiratomik) untuk menghalang pelaksanaan serentak. - Gunakan fail keadaan (fail penanda bagi setiap langkah) untuk membolehkan sambungan semula selepas kegagalan.
Corak percubaan semula dengan penangguhan:
- Sentiasa tetapkan bilangan percubaan maksimum — jangan mencuba semula selama-lamanya.
- Gunakan penangguhan eksponen: gandakan kelewatan selepas setiap kegagalan.
- Tambahkan jiter (kerawakan) untuk mencegah penyegerakan kumpulan besar.
- Bezakan ralat sementara (cuba semula) daripada ralat kekal (gagal dengan segera).
Menggabungkan corak ini menghasilkan skrip bertaraf produksi: selamat, boleh diperhatikan dan mampu memulihkan diri.
Pelajari Bash dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 22
- Pelajaran
- 88
Soalan Lazim
Adakah pelajaran “Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan” percuma?
Ya — teks penuh “Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Penguasaan Baris Perintah Linux & Penskripan Bash, tingkat taraf kepada CoddyKit PRO. Kursus Penguasaan Baris Perintah Linux & Penskripan Bash merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan”?
Reka bentuk operasi yang selamat untuk dijalankan semula dan tambahkan penangguhan eksponen bagi panggilan luaran yang tidak stabil Anda berlatih Penguasaan Baris Perintah Linux & Penskripan Bash menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Penguasaan Baris Perintah Linux & Penskripan Bash?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Penguasaan Baris Perintah Linux & Penskripan Bash di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.
Berapa lamakah pelajaran “Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Penguasaan Baris Perintah Linux & Penskripan Bash ini?
Ya. Setiap pelajaran Penguasaan Baris Perintah Linux & Penskripan Bash menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Mod Ketat dengan set -euo pipefail
- Pengendali Trap untuk Pembersihan dan Isyarat
- Fail Sementara Selamat dan Direktori Kunci
- Skrip Idempoten dan Logik Percubaan Semula dengan Penangguhan