İçindekiler
- Problem
- Nasıl çalışıyor
- Tasarım kararları ve alternatifler
- Çalıştırma geçmişi ne gösteriyor
- Gerçek bir kesinti ve kendi kendini kapatan bir izleyici
- Sınırlar
Problem
Reponun README'si neden var olduğunu iki cümlede anlatıyor. 23 Temmuz 2026'da muhittincamdali.com
kapandı ve yaklaşık üç buçuk gün kapalı kaldı, çünkü tüm izleme siteyle aynı sunucuda çalışıyordu.
Sunucuya ulaşılamadığında, bunu haber verecek hiçbir şeye de ulaşılamıyordu.
Çözüm, başka bir yerde duran bir kontrol. site-uptime tamamen GitHub Actions üzerinde çalışıyor:
sunucu yok, her workflow'un aldığı token dışında secret yok, bir izleme servisinde hesap yok. İlk
commit 3 Ağustos 2026 tarihli; repoda üç commit ve toplamda yaklaşık 110 satır YAML'dan oluşan iki
workflow var.
Nasıl çalışıyor
uptime.yml, cron: "*/5 * * * *" ile zamanlanmış ve elle de başlatılabiliyor. Her çalıştırma iki
URL istiyor, ana sayfa ve /api/health/; siteyi ancak ikisi de HTTP 200 dönerse ayakta sayıyor.
Başarısız bir deneme, sayılmadan önce 30 saniye sonra bir kez tekrarlanıyor:
sh
1probe() {2 HOME_CODE=$(curl -s -o /dev/null -w "%{http_code}" -m 20 "$SITE/" || echo 000)3 HEALTH_CODE=$(curl -s -o /dev/null -w "%{http_code}" -m 20 "$SITE/api/health/" || echo 000)4 echo "home=$HOME_CODE health=$HEALTH_CODE"5 [ "$HOME_CODE" = "200" ] && [ "$HEALTH_CODE" = "200" ]6}İki URL'e bakmak iki farklı arızayı ayırıyor. Ana sayfa sunulurken arkasındaki uygulama bozuk
olabilir; health endpoint'i bunu kapsıyor. -m 20 her isteği 20 saniyeyle sınırlıyor,
|| echo 000 ise bağlantı hatasını karşılaştırmanın işleyebileceği bir durum koduna çeviriyor.
Tasarım kararları ve alternatifler
Uyarı ve durum olarak bir issue. İki deneme de başarısız olduğunda workflow outage etiketli açık
bir issue arıyor. Yoksa zamanı, kontrol ettiği URL'leri ve kısa bir müdahale rehberini içeren bir
issue açıyor; varsa "still down" yorumu ekliyor. Site yeniden cevap verdiğinde yorum yazıp issue'yu
kapatıyor:
sh
1EXISTING=$(gh issue list --repo "$REPO" --state open --label outage --json number --jq '.[0].number // empty')2if [ -n "$EXISTING" ]; then3 NOW=$(date -u +"%Y-%m-%d %H:%M UTC")4 gh issue comment "$EXISTING" --repo "$REPO" --body "✅ RECOVERED at $NOW — site and health endpoint both 200."5 gh issue close "$EXISTING" --repo "$REPO"6fiIssue başlığı ilk hatanın zamanını taşıyor; gövdedeki müdahale rehberi önce nereye bakılacağını
sıralıyor: barındırma hesabı, sunucunun ağ durumu ve uygulama servisi, ayrıca Temmuz'daki olaya bir
atıf. Bir çalıştırma Actions sekmesinden elle de başlatılabiliyor (*Site Uptime Check* →
*Run workflow*); site geri geldiğinde bunu doğrulamanın en hızlı yolu bu.
Bu, ek bir depolama olmadan üç şey sağlıyor. Kesinti başına yalnızca bir uyarı açılıyor, çünkü açık
issue kesintinin sürdüğünün kaydı. İletimi GitHub yapıyor: README'ye göre yeni bir issue sahibine
e-posta gönderiyor. Issue'nun yorumları da her başarısız çalıştırma için zaman damgası taşıyan
kesinti kaydına dönüşüyor.
Alternatifler barındırılan bir izleme servisi ya da ikinci bir makinede çalışan küçük bir kontroldü.
İkisi de işe yarar ama ikisi de bakımı gereken bir şey ekliyor: bir hesap, bir sunucu, kimlik
bilgileri. Buradaki asıl amaç, izlediği sunucuyla hiçbir şey paylaşmayan bir kontroldü; GitHub zaten
kodun bulunduğu yer.
İşe yarayan en küçük izinler. Workflow issues: write ve contents: read tanımlıyor ve yalnızca
github.token kullanıyor. Başarısız bir çalıştırma ayrıca exit 1 ile bitiyor; böylece kesinti
sırasında yalnızca issue değil, Actions sekmesi de kırmızı çalıştırmalar gösteriyor.
Çakışan çalıştırma yok. concurrency: group: uptime ve cancel-in-progress: false, hâlâ tekrar
deneyen bir çalıştırmanın arkasındakini iptal etmek yerine sıraya koyuyor. Aksi hâlde aynı anda
çalışan iki çalıştırma da "açık issue yok" görüp iki issue açabilirdi.
Çalıştırma geçmişi ne gösteriyor
Zamanlama her beş dakika diyor. Bu günde 288 çalıştırma demek. GitHub'ın dokümantasyonu bu konuda
temkinli: Actions yoğun yük altındayken zamanlanmış çalıştırmalar gecikebiliyor ve sıradaki bazı
çalıştırmalar düşürülebiliyor. Reponun kendi çalıştırma geçmişi bunun ne kadar önemli olduğunu
gösteriyor.
15 Ekim 2026 itibarıyla uptime workflow'u 3 Ağustos'tan beri toplam 1.082 kez çalışmıştı. Son 200
çalıştırmada zamanlanmış çalıştırmalar arasındaki aralıklar şöyleydi:
Dönem | Zamanlanmış çalıştırma | Medyan aralık | En kısa | En uzun |
|---|---|---|---|---|
8–19 Eylül 2026 | 83 | 184 dk | 100 dk | 355 dk |
20 Eylül–2 Ekim 2026 | 73 | 248 dk | 104 dk | 498 dk |
5–15 Ekim 2026 | 43 | 319 dk | 151 dk | 585 dk |
Yani kontrol beş dakikada bir değil, birkaç saatte bir çalışıyor. Bu site için yine de önemli fark
bu: Temmuz'daki kesinti günlerce fark edilmedi, sonraki ise onu gören ilk çalıştırma tarafından
raporlandı; o çalıştırma site kapandıktan saatler sonra gelmiş olsa bile.
Gerçek bir kesinti ve kendi kendini kapatan bir izleyici
28–30 Eylül 2026. İlk başarısız çalıştırma 28 Eylül'de 07:34 UTC'de geldi ve #1 numaralı issue
bir dakika sonra açıldı. Sonraki iki buçuk günde on çalıştırma daha başarısız oldu ve her biri bir
"still down" yorumu ekledi. 30 Eylül 18:36 UTC'deki çalıştırma iki URL'in de 200 döndüğünü gördü,
yorum yazıp issue'yu kapattı. Kaydın tamamı issue ve yorumları; repo kesintinin nedenini söylemiyor,
bu yazı da söylemiyor.
2 Ekim 2026. İki gün sonra GitHub "Site Uptime Check" workflow'unu kapattı. GitHub, public
repolarda 60 gün repo aktivitesi olmayınca zamanlanmış workflow'ları kapatıyor ve tek commit
3 Ağustos tarihliydi. #1 numaralı issue'ya yorum yazanlar dahil zamanlanmış çalıştırmaların kendisi
workflow'u canlı tutmadı. Sessizce duran bir izleyici hiç olmamasından kötü, çünkü hâlâ kurulu
görünüyor.
5 Ekim'de commit'lenen çözüm, ayda bir commit atan ikinci bir workflow. Contents API üzerinden
.github/keepalive dosyasına bir zaman damgası yazıyor:
sh
1FILE=.github/keepalive2STAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")3SHA=$(gh api "repos/$GITHUB_REPOSITORY/contents/$FILE" --jq .sha 2>/dev/null || true)4gh api -X PUT "repos/$GITHUB_REPOSITORY/contents/$FILE" \5 -f message="chore: keepalive $STAMP" \6 -f content="$(printf '%s\n' "$STAMP" | base64)" \7 ${SHA:+-f sha="$SHA"} > /dev/null${SHA:+-f sha="$SHA"} mevcut dosyanın SHA'sını yalnızca dosya varsa geçiyor; böylece ilk
çalıştırma dosyayı oluşturuyor, sonrakiler güncelliyor. Workflow contents: write istiyor ve üçüncü
taraf action kullanmıyor. Dosyadaki yorum bir ayrıntıya daha dikkat çekiyor: GITHUB_TOKEN ile
atılan bir commit başka workflow'ları başlatmıyor, yani keepalive bir çalıştırma zinciri
tetikleyemiyor. İlk keepalive commit'i aynı akşam elle başlatılan bir çalıştırmayla atıldı;
1 Kasım'dan itibaren zamanlama (17 6 1 * *) devralıyor.
Sınırlar
- Çözünürlük dakika değil saat. Yukarıda ölçülen aralıklar beklenmesi gerekenler. İki çalıştırma
arasındaki kısa bir kesinti hiç görülmüyor.
- GitHub'a bağlı. GitHub Actions ya da issue bildirimleri çalışmıyorsa uyarı da çalışmıyor.
Amaç her şeyden değil, sitenin sunucusundan bağımsız olmak olduğu için bu kabul edilebilir.
- Tek konum, iki durum kodu. Kontrol GitHub'ın runner'larından çalışıyor ve yalnızca durum
kodlarını karşılaştırıyor. Sayfa içeriğine, yanıt süresine ya da sertifika süresine bakmıyor.
- Keepalive henüz tam bir döngüyle kanıtlanmadı. Kapanmadan sonra eklendi; zamanlamayı sonraki
60 günlük pencerede canlı tutup tutmadığı çalıştırma geçmişinde görülecek.
- Tek amaçlı. Site URL'i workflow'un içine yazılmış ve reponun lisans dosyası yok. Bu, tek bir site
için çalışan bir düzen; yeniden kullanılabilir bir araç değil.
Kaynak kod: github.com/muhittincamdali/site-uptime

