Rule Servisi
Rule Servisi, Cınga veri hattındaki ölçüm katmanlarını (raw, synth, window, status-register) kural tablosuna göre değerlendiren ve koşul sağlandığında aksiyon üreten karar mikroservisidir.
Bu servis hesap motorlarının yerine geçmez; hesaplanmış veriyi ve register bitlerini okuyup iş kuralı çalıştırır.
Sorumluluk
raw.persisted.v1,synth.ready.v1,window.ready.v1,heartbeat.status.changed.v1eventlerini tüketmek- Kural snapshot’ını (cihaz özel > global) çözmek
- Koşulları değerlendirmek (threshold, trend, bitmask, kombinasyon)
- Kural tetiklenince aksiyon üretmek (alarm, komut, bildirim, kayıt)
- Sonuçları audit trail’e yazmak
Kural Kaynakları
- Grup tablosu:
rule_groups - Kural tablosu:
rules - Kural cache: Redis
rules:{device_id}:latest/rules:0:latest - Öncelik:
- Cihaz özel kural
- Global kural
İşlem Akışı
Kural Tipleri (V1)
- Threshold kuralı (
value > limit,value < limit) - Trend kuralı (
slope,r2,p95bazlı) - Status-bit kuralı (
STATUS_FAULT_*,STATUS_P_HIGHvb.) - Kompozit kural (
AND/ORile çoklu kaynak) - Süre koşulu (
condition true for X min)
Aksiyon Tipleri (V1)
ALERT_CREATE(Observer/notification pipeline)DEVICE_COMMAND_REQUEST(kontrollü komut akışı)RULE_TAG_WRITE(durum etiketleme)AUDIT_ONLY(yalnız kayıt)
Not: Cihaz komutu doğrudan Rule Servisi içinden gönderilmez; komut ayrı kontrol katmanına event ile devredilir.
Aksiyon yürütme katmanı için bkz: Action Executor Servisi.
Çoklu Aksiyon Modeli (Action Plan)
Tek action_id yerine plan tabanlı model kullanılır:
trigger_action_plan_idreset_action_plan_id
Bir action plan içinde birden fazla aksiyon adımı olabilir:
- WhatsApp mesajı
- E-posta
- Mobil push
- Webhook
- Audit kaydı
Bu sayede tek kural tetiğiyle çoklu kanal orkestrasyonu yapılır.
Veri Modeli (Group + Rules)
rule_groups
Birden fazla koşul tek bir grubu tetikleyebilir. Aksiyon ve mesaj davranışı grup seviyesinde yönetilir.
| Kolon | Tip | Not |
|---|---|---|
id | bigint PK | |
device_id | varchar(21) | 0 global |
name | varchar(100) | |
description | varchar(255) | |
status | boolean | grup aktif/pasif |
multi_trigger | boolean | false=edge, true=level |
notify_on_reset | boolean | normale dönünce event/mesaj |
trigger_count | bigint | toplam tetik sayacı |
trigger_action_plan_id | bigint | trigger aksiyon planı |
reset_action_plan_id | bigint | reset aksiyon planı |
trigger_message_id | bigint | trigger mesaj şablonu |
reset_message_id | bigint | reset mesaj şablonu |
publish_bit | smallint | publish gate biti (99=always publish) |
cooldown_sec | integer | tekrar tetik engeli |
priority | integer | düşük sayı daha öncelikli |
valid_from, valid_to | timestamptz | aktiflik penceresi |
rule_version | integer | |
rule_hash | varchar(64) | |
last_state | varchar(16) | normal/triggered |
last_changed_at | timestamptz | son state geçişi |
created_at, updated_at | timestamptz |
rules
Grup altındaki atomik koşul kayıtları.
| Kolon | Tip | Not |
|---|---|---|
id | bigint PK | |
group_id | bigint FK | rule_groups.id |
variable_id | varchar(30) | ölçülen alan |
source_scope | varchar(16) | raw/synth/window/status |
condition_type | varchar(16) | threshold/bit_set/bit_change/range/trend |
operator | varchar(8) | >,<,>=,<=,=,!= |
value | double precision | eşik |
duration_sec | integer | koşulun sağlanma süresi |
logic | varchar(4) | AND/OR |
bit_index | smallint | status bit koşulları için |
bit_expected | boolean | status bit beklenen değer |
window_type | varchar(16) | window kuralları için |
old_register_value | bigint | edge/pulse kontrolü |
new_register_value | bigint | edge/pulse kontrolü |
status | boolean | kural aktif/pasif |
created_at, updated_at | timestamptz |
action_plans
| Kolon | Tip | Not |
|---|---|---|
id | bigint PK | |
name | varchar(100) | plan adı |
status | boolean | aktif/pasif |
dedup_scope | varchar(32) | device/group/global |
cooldown_sec | integer | plan seviyesinde cooldown |
created_at, updated_at | timestamptz |
Not: Plan adımlarının gerçek hedefe çözülmesi Action Executor tarafında recipient_profiles/recipient_channels/action_routes tabloları üzerinden yapılır (bkz: /projects/cinga/backend/architecture/action-executor).
action_plan_steps
| Kolon | Tip | Not |
|---|---|---|
id | bigint PK | |
plan_id | bigint FK | action_plans.id |
step_order | integer | çalıştırma sırası |
channel_type | varchar(32) | whatsapp/email/push/webhook/audit |
template_id | bigint | mesaj şablonu |
config_json | jsonb | kanal ayarı / hedef |
retry_policy_json | jsonb | retry/backoff |
enabled | boolean | aktif/pasif |
created_at, updated_at | timestamptz |
message_templates
| Kolon | Tip | Not |
|---|---|---|
id | bigint PK | |
channel_type | varchar(32) | |
name | varchar(100) | |
subject_tpl | text | e-posta/başlık için |
body_tpl | text | render şablonu |
locale | varchar(8) | tr/en |
created_at, updated_at | timestamptz |
Locked Group Semantics (V1)
multi_trigger davranışı
multi_trigger = false(edge mode)- Grup
normal -> triggeredgeçişinde bir kez trigger event üretir. - Grup
triggered -> normalgeçişinde (venotify_on_reset=true) reset event üretir.
- Grup
multi_trigger = true(level mode)- Koşul true olduğu her değerlendirmede trigger event üretilebilir.
cooldown_seczorunlu uygulanır.
notify_on_reset davranışı
true: koşul düzelince reset event/mesaj üret.false: reset sessiz geçsin, yalnız state güncellensin.
publish_bit davranışı
publish_bit = 99-> her durumda mesaj publish edilir.- Diğer değerler için
PUBLISH_STATUSregister bit map'ine göre bit kontrolü yapılır. PUBLISH_STATUSalanı status register sözlüğünün publish bölümüyle aynı bit sıralamasını kullanır.- Bit mapping kaynağı:
/projects/cinga/backend/architecture/status-register. - Bit kapalıysa:
- aksiyon audit/log yine çalışabilir,
- dış mesaj publish edilmez.
Fault / Pulse / Status yorumu
- Status fault bitleri (
STATUS_FAULT_*) level mantığıyla değerlendirilir (düzelene kadar true). P_RISE,P_DROPpulse/event mantığıyla değerlendirilir.status_pumpfiziksel çalışma feedback'i olarak yorumlanır.
Group State Machine
Publish Gate Akışı
Dinamik Mesaj İçeriği (Template Render)
Kural tetiklenince gönderilecek mesajlar template üzerinden render edilir.
Örnek template:
Basınç limiti {{limit_bar}} bar, anlık {{current_bar}} bar ({{delta_bar}} bar aşım).
Önerilen render context:
device_idrule_namemetriccurrent_valuelimit_valuedeltaunittimestamp
Örnek render sonucu:
Basınç limiti 3.0 bar, anlık 4.5 bar (1.5 bar aşım).
Action Orchestration Akışı
Not: Rule Servisi step'leri doğrudan çalıştırmaz; yalnız action.execute.requested.v1 üretir. Kanal bazlı yürütme ayrı Action Executor katmanında yapılır.
Action Sonucu Geri Besleme Politikası
Rule Servisi action.executed.v1 ve action.failed.v1 eventlerini izleyerek grup state ve escalation kararlarını günceller.
action.executed.v1-> ilgili step tamamlandı olarak işaretlenir.action.failed.v1-> retry/dead-letter durumuna göre escalation akışı değerlendirilir.- Aynı
evaluation_key + step_orderiçin idempotent sonuç işlenir.
Execution Boundary Contract (Rule vs Executor vs Communication)
Sorumluluk sınırı kesin kural:
- Rule Servisi: yalnız karar verir ve
action.execute.requested.v1üretir. - Action Executor: kanal/adım yürütmesini yapar (push/email/whatsapp/webhook/audit).
- Communication: sadece cihaza downlink komut iletimini yürütür.
Rule Servisi hiçbir kanala doğrudan mesaj göndermez ve cihaza doğrudan komut basmaz.
Topic ve Event Standardı
- Topic:
cinga.rule.evaluatedcinga.rule.triggeredcinga.action.requestedcinga.rule.failed
- Event:
rule.evaluated.v1rule.triggered.v1action.execute.requested.v1rule.failed.v1
Event Örnekleri
rule.triggered.v1
{
"event": "rule.triggered.v1",
"meta": {
"schema_version": 1,
"trace_id": "rule-9f3f...",
"producer_service": "rule-service",
"produced_at": "2026-03-12T20:30:21.120Z",
"process_ms": 15
},
"context": {
"device_id": "400000011D081B70",
"stream_id": 9823412
},
"data": {
"group_id": 12,
"rule_id": 114,
"event_type": "trigger",
"rule_hash": "a8be...",
"source_event": "window.ready.v1",
"trigger_reason": "P95_RTT_HIGH",
"severity": "high",
"trigger_count": 57,
"actions": ["ALERT_CREATE", "AUDIT_ONLY"]
},
"error": null
}
rule.triggered.v1 (reset örneği)
{
"event": "rule.triggered.v1",
"meta": {
"schema_version": 1,
"trace_id": "rule-9f3f...",
"producer_service": "rule-service",
"produced_at": "2026-03-12T20:40:21.120Z",
"process_ms": 12
},
"context": {
"device_id": "400000011D081B70",
"stream_id": 9823519
},
"data": {
"group_id": 12,
"rule_id": 114,
"event_type": "reset",
"rule_hash": "a8be...",
"source_event": "window.ready.v1",
"trigger_reason": "P_HIGH_NORMALIZED",
"severity": "info",
"trigger_count": 58,
"actions": ["AUDIT_ONLY"]
},
"error": null
}
action.execute.requested.v1
{
"event": "action.execute.requested.v1",
"meta": {
"schema_version": 1,
"trace_id": "rule-9f3f...",
"producer_service": "rule-service",
"produced_at": "2026-03-12T20:30:21.135Z",
"process_ms": 15
},
"context": {
"device_id": "400000011D081B70",
"stream_id": 9823412
},
"data": {
"group_id": 12,
"rule_id": 114,
"action_plan_id": 21,
"step_order": 1,
"action_type": "ALERT_CREATE",
"channel_type": "whatsapp",
"payload": {
"title": "High pressure trend",
"metric": "P_HIGH",
"current_bar": 4.5,
"limit_bar": 3.0,
"delta_bar": 1.5,
"severity": "high",
"message": "Basınç limiti 3.0 bar, anlık 4.5 bar (1.5 bar aşım)."
}
},
"error": null
}
rule.failed.v1
{
"event": "rule.failed.v1",
"meta": {
"schema_version": 1,
"trace_id": "rule-9f3f...",
"producer_service": "rule-service",
"produced_at": "2026-03-12T20:30:21.180Z",
"process_ms": 15
},
"context": {
"device_id": "400000011D081B70",
"stream_id": 9823412
},
"data": null,
"error": {
"failed_stage": "rule_evaluation",
"error_code": "RULE_CONDITION_INVALID",
"error_message": "unknown variable: P95_X",
"retryable": false,
"failed_at": "2026-03-12T20:30:21Z"
}
}
Operasyon Notları
- Kural değerlendirme idempotent olmalıdır (
event_id + group_id + rule_id). evaluation_keyönerisi:sha1(event_id|group_id|rule_id|event_type).- Cooldown mekanizması zorunludur (alarm fırtınasını önlemek için).
- Cooldown öncelik sırası:
group.cooldown_sec->action_plan.cooldown_sec. - Group içinde AND/OR precedence soldan-sağa değerlendirilir; kısa devre (short-circuit) uygulanır.
- Rule değişikliklerinde cache invalidation zorunludur.
- Dry-run modu desteklenmelidir (aksiyon üretmeden sadece evaluate).
event_typealanıtriggerveyaresetolarak standartlaştırılmalıdır.
Örnek Kural Setleri (V1)
1) Yüksek Gerilim Alarmı
- Group:
VOLTAGE_HIGH_ALERT - Scope:
raw - Koşul:
VRMS_R > 250 OR VRMS_S > 250 OR VRMS_T > 250 multi_trigger=false,notify_on_reset=true- Trigger aksiyon planı: WhatsApp + Push + Audit
- Reset aksiyon planı: Push + Audit
2) Pompa Çalışırken Akım Dengesizliği Yüksek
- Group:
PUMP_ON_IIMB_HIGH - Scope:
synth + status - Koşul:
status_pump == truei_imb > 20duration_sec >= 30
multi_trigger=true,cooldown_sec=300- Trigger aksiyon planı: WhatsApp + Email + Audit
- Reset aksiyon planı: Audit (opsiyonel notify)
3) MP/TH Fault Kritik Alarmı
- Group:
MOTOR_PROTECTION_FAULT - Scope:
status - Koşul:
STATUS_FAULT_MP == 1 OR STATUS_FAULT_TH == 1 multi_trigger=false,notify_on_reset=true- Trigger aksiyon planı: WhatsApp + Email + Webhook + Audit
- Reset aksiyon planı: WhatsApp (resolved) + Audit
Servis Bazlı SLO Hedefleri (Öneri)
| Metrik | Hedef |
|---|---|
p95 rule_evaluation_ms | < 200ms |
rule evaluation success rate | > 99.5% |
duplicate trigger rate | < 0.1% |
cooldown violation | 0 |
Çıktı
Rule Servisi çıktısı:
- Kural değerlendirme kayıtları
- Tetiklenen aksiyon eventleri
- Hata durumunda rule-failed görünürlüğü