Heartbeat Servisi
Heartbeat Servisi, GSM IoT cihazlarının canlılık durumunu periyodik toplu ping kontrolü ile izleyen mikroservistir.
Amaç; hangi cihazın ayakta, hangi cihazın gecikmeli, hangi cihazın offline olduğunu sürekli takip etmek ve bu durumu hem operasyon ekranına hem de event hattına taşımaktır.
Sorumluluk
- Sabit IP'li cihazlara tanımlı periyotlarda toplu ping göndermek
- Ping RTT/timeout sonuçlarını toplamak
last_seen,rtt_ms,missed_countgibi canlılık metriklerini güncellemek- Cihaz durumunu sınıflandırmak:
online,degraded,offline - Durum değişimlerinde event üretmek
- Kritik durumlarda alarm mekanizmasını tetiklemek
Durum Modeli
online: RTT eşik altında ve timeout yokdegraded: ping yanıtı var ama RTT yüksekoffline: timeout penceresinde yanıt yok
Önerilen eşikler (başlangıç):
- heartbeat period:
60s - degraded RTT threshold:
>1500ms - offline timeout:
>5000msveya ardışıkmissed_count >= 3
Eşikler environment bazında config ile yönetilmelidir (dev/stage/prod):
heartbeat_period_msdegraded_rtt_msoffline_timeout_msoffline_missed_count
İşlem Akışı
Veri Kaynakları
- Redis
device_liveness:{device_id}(anlık durum cache)
- DB
device_heartbeat_status(kalıcı tarihçe/raporlama)
- Kafka
- heartbeat eventleri (durum değişimi + metrik güncelleme)
Önerilen Redis Key Yapısı
device_liveness:{device_id}(anlık son durum)heartbeat:raw:{yyyy-mm-dd}:{device_id}(gün içi periodik ölçüm seti)
{
"device_id": "400000011D081B70",
"status": "online",
"last_ping_at": "2026-03-12T19:20:00Z",
"last_seen": "2026-03-12T19:20:01Z",
"rtt_ms": 820,
"missed_count": 0,
"updated_at": "2026-03-12T19:20:01Z"
}
Retention:
device_liveness:{device_id}: TTL yok (anlık state key'i kalıcı)heartbeat:raw:{day}:{device_id}: 48 saat TTL (gün sonu aggregate sonrası temizlenir)
Tek Tablo Politikası (DB)
Heartbeat için DB tarafında tek tablo kullanılır ve her ping DB'ye yazılmaz.
- Gün içi heartbeat detayları yalnız Redis'te tutulur.
- DB'ye yalnız gün sonu özet satırı yazılır.
- Bu nedenle per-ping insert/update yapılmaz.
Önerilen tek DB tablo: device_heartbeat_daily
| Kolon | Tip | Not |
|---|---|---|
day | date | Gün (UTC) |
device_id | varchar(21) | |
online_ratio | double precision | Günlük online oranı |
degraded_ratio | double precision | Günlük degraded oranı |
offline_ratio | double precision | Günlük offline oranı |
avg_rtt_ms | double precision | Günlük ortalama RTT |
p95_rtt_ms | double precision | Günlük p95 RTT |
max_missed_count | integer | Gün içi en yüksek missed |
calc_version | integer | |
created_at, updated_at | timestamptz |
DB Şişmesini Önleme (Retention + Gün Sonu Özet)
Heartbeat verisi yüksek frekansta üretildiği için ham periodik kayıtlar DB'ye yazılmaz.
Final politika:
- Gün içi periodik heartbeat detayları Redis'te tutulur.
- Gün sonu
UTC 00:05'te aggregate job çalışır. - Geç gelen veriler için
late_tolerance = 10 dkuygulanır (00:15'e kadar dahil). - Aggregate tamamlanınca yalnız günlük özet satırı
device_heartbeat_dailytablosuna yazılır. - Redis'teki bir önceki günün periodik detayları temizlenir.
Böylece UI anlık durumu Redis'ten hızlı okur, uzun dönem trendleri tek tablo günlük özetten gösterir.
Gün Sonu Job Retry / Backfill Politikası
Gün sonu aggregate job başarısız olursa veri kaybı olmaması için aşağıdaki politika uygulanır:
-
Retry
- İlk başarısızlıkta
exponential backoffile otomatik retry (örn. 1dk, 5dk, 15dk) - Maksimum retry sayısı aşıldığında
heartbeat.failed.v1üretilir.
- İlk başarısızlıkta
-
Backfill
- Bir sonraki başarılı çalışmada eksik gün(ler) backfill edilir.
- Backfill aralığı: son
Ngün (öneri:N=7). - Aynı
day + device_idiçin idempotent upsert uygulanır.
-
Temizlik Güvencesi
- Redis
heartbeat:raw:{day}:{device_id}temizliği yalnız DB upsert başarıyla tamamlandıktan sonra yapılır. - Başarısızlıkta raw key korunur, sonraki backfill run’ında tekrar işlenir.
- Redis
Topic ve Event Standardı
- Kafka topic:
cinga.heartbeat.metricscinga.heartbeat.statuscinga.heartbeat.failed
- Event:
heartbeat.metrics.updated.v1heartbeat.status.changed.v1heartbeat.failed.v1
Not: Heartbeat eventleri Observer tarafından da dinlenir. Böylece cihaz canlılık durumu, pipeline metrikleriyle birlikte tek gözlem katmanında izlenebilir.
Event Örnekleri
heartbeat.metrics.updated.v1
{
"event": "heartbeat.metrics.updated.v1",
"meta": {
"schema_version": 1,
"trace_id": "hb-9f3f...",
"producer_service": "heartbeat-service",
"produced_at": "2026-03-12T19:20:01.120Z",
"process_ms": 9
},
"context": {
"device_id": "400000011D081B70"
},
"data": {
"status": "online",
"rtt_ms": 820,
"missed_count": 0,
"last_seen": "2026-03-12T19:20:01Z"
},
"error": null
}
heartbeat.status.changed.v1
{
"event": "heartbeat.status.changed.v1",
"meta": {
"schema_version": 1,
"trace_id": "hb-9f3f...",
"producer_service": "heartbeat-service",
"produced_at": "2026-03-12T19:25:01.050Z",
"process_ms": 11
},
"context": {
"device_id": "400000011D081B70"
},
"data": {
"previous_status": "online",
"current_status": "offline",
"missed_count": 5,
"last_seen": "2026-03-12T19:20:01Z"
},
"error": null
}
heartbeat.failed.v1
{
"event": "heartbeat.failed.v1",
"meta": {
"schema_version": 1,
"trace_id": "hb-9f3f...",
"producer_service": "heartbeat-service",
"produced_at": "2026-03-12T19:21:00.300Z",
"process_ms": 14
},
"context": {
"device_id": "400000011D081B70"
},
"data": null,
"error": {
"failed_stage": "heartbeat",
"error_code": "HEARTBEAT_PING_TIMEOUT",
"error_message": "icmp ping timeout exceeded",
"retryable": true,
"failed_at": "2026-03-12T19:21:00Z"
}
}
Çıktı
Heartbeat Servisinin çıktısı:
- Cihaz canlılık state’i (Redis + DB)
- Kafka’da heartbeat metrik ve durum eventleri
- Offline/degraded durumlarında alarm tetik bilgisi