Skip to main content

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_count gibi 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 yok
  • degraded: ping yanıtı var ama RTT yüksek
  • offline: timeout penceresinde yanıt yok

Önerilen eşikler (başlangıç):

  • heartbeat period: 60s
  • degraded RTT threshold: >1500ms
  • offline timeout: >5000ms veya ardışık missed_count >= 3

Eşikler environment bazında config ile yönetilmelidir (dev/stage/prod):

  • heartbeat_period_ms
  • degraded_rtt_ms
  • offline_timeout_ms
  • offline_missed_count

İşlem Akışı

Veri Kaynakları

  1. Redis
    • device_liveness:{device_id} (anlık durum cache)
  2. DB
    • device_heartbeat_status (kalıcı tarihçe/raporlama)
  3. 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

KolonTipNot
daydateGün (UTC)
device_idvarchar(21)
online_ratiodouble precisionGünlük online oranı
degraded_ratiodouble precisionGünlük degraded oranı
offline_ratiodouble precisionGünlük offline oranı
avg_rtt_msdouble precisionGünlük ortalama RTT
p95_rtt_msdouble precisionGünlük p95 RTT
max_missed_countintegerGün içi en yüksek missed
calc_versioninteger
created_at, updated_attimestamptz

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 dk uygulanır (00:15'e kadar dahil).
  • Aggregate tamamlanınca yalnız günlük özet satırı device_heartbeat_daily tablosuna 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:

  1. Retry

    • İlk başarısızlıkta exponential backoff ile otomatik retry (örn. 1dk, 5dk, 15dk)
    • Maksimum retry sayısı aşıldığında heartbeat.failed.v1 üretilir.
  2. Backfill

    • Bir sonraki başarılı çalışmada eksik gün(ler) backfill edilir.
    • Backfill aralığı: son N gün (öneri: N=7).
    • Aynı day + device_id için idempotent upsert uygulanır.
  3. 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.

Topic ve Event Standardı

  • Kafka topic:
    • cinga.heartbeat.metrics
    • cinga.heartbeat.status
    • cinga.heartbeat.failed
  • Event:
    • heartbeat.metrics.updated.v1
    • heartbeat.status.changed.v1
    • heartbeat.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