- Published on
Production Reliability Design dengan C++
- Authors
π Artikel 7: Production Reliability Design dengan C++
Posisi: Artikel 7 dari 8 Domain Keputusan: Reliability & Error Model Status Lock: π Reliability & Error Handling Freeze Entry Context: IndustrialNode/IndustrialNode.ino
- π Artikel 7: Production Reliability Design dengan C++
1. Problem Reality
Setelah Artikel 6:
- Layering terkunci.
- Allocation disiplin.
- Concurrency terkendali.
- Communication terisolasi.
Firmware terlihat matang.
Namun di lapangan muncul gejala:
- βKadang mati sendiri.β
- βKadang tidak kirim data.β
- βKadang relay tidak sesuai status.β
- Watchdog reset tanpa log jelas.
- OTA gagal tanpa error code formal.
Masalah paling sering:
- Error hanya di-print ke Serial.
- Fungsi gagal tapi tidak dipropagasi.
- Relay tetap ON saat sensor error (fail-open).
- Tidak ada status sistem global yang eksplisit.
Masalahnya bukan arsitektur lagi.
Masalahnya:
Tidak ada model reliability formal.
2. Root Cause Analysis
Reliability rusak bukan karena satu bug, tetapi karena tidak ada struktur error.
2.1 Silent Failure
Contoh:
if (!sensor.read()) {
Serial.println("Sensor error");
}
Function gagal, tetapi:
- Tidak ada return status.
- Tidak ada perubahan state.
- Tidak ada fail-safe.
System berjalan seolah-olah normal.
2.2 Watchdog Tanpa Owner
esp_task_wdt_reset(); // dipanggil di banyak tempat - β
Watchdog di-feed dari banyak domain.
Jika deadlock terjadi di satu task:
- Task lain masih feed watchdog.
- Hang tidak terdeteksi.
2.3 Fail-Open Control
Jika sensor gagal:
- Relay tetap ON.
- Heater tetap aktif.
- Motor tetap berputar.
Software terlihat βhidupβ, hardware rusak perlahan.
2.4 Logging Tidak Terstruktur
Serial.println("WiFi error");
Serial.println("Temp fail");
Tidak ada:
- Severity level
- Error code
- Aggregation
- Telemetry integration
Ketika device di lapangan:
- Tidak ada audit trail.
π Visualisasi Error Tanpa Propagasi


Tanpa error model:
- Failure tidak naik ke Application.
- Fail-safe tidak pernah aktif.
- System terlihat normal hingga terlambat.
3. Design Principle (Rule yang Dikunci)
Artikel 7 mengunci reliability baseline final.
π Rule 1 β Error Propagation via Explicit Status
Semua fungsi kritikal harus:
- Return
Statusenum atau - Update error state internal
Contoh:
enum class Status {
OK,
SENSOR_ERROR,
COMM_ERROR,
STORAGE_ERROR,
INTERNAL_ERROR
};
Tidak boleh:
- β Silent failure
- β Ignore return value
π Rule 2 β No Exception
Exception dilarang.
Alasan:
- Stack tidak terprediksi.
- Flow tersembunyi.
- Tidak deterministik.
Error flow harus eksplisit.
π Rule 3 β Watchdog Encapsulated
Watchdog harus dikelola oleh satu class:
svc_HealthService
Tidak boleh di-feed sembarang tempat.
π Rule 4 β Fail-Safe State Mandatory
Jika error kritikal terjadi:
- System masuk state FAILSAFE.
- Relay ke default aman.
- Control loop tetap berjalan dalam mode terbatas.
Tidak boleh fail-open.
π Rule 5 β Logging via Interface Only
Tidak boleh:
Serial.printlnliar di semua file.- Logging blocking di ControlTask.
Harus:
ILoggerinterface- Bisa redirect (Serial / MQTT / disable)
- Non-blocking via queue
π Rule 6 β Health Telemetry Mandatory
Minimal metric:
- reset_reason
- heap_min_free
- backlog_depth
- wifi_state
- error_code
Harus masuk telemetry.
Setelah Artikel 7:
- β Tidak boleh direct printf liar
- β Tidak boleh exception
- β Tidak boleh silent failure
- β Tidak boleh fail-open control
Reliability baseline final.
4. Implementation Pattern (ESP32 Arduino Context)
4.1 Error Enum Pattern
enum class Status {
OK,
SENSOR_ERROR,
COMM_ERROR,
STORAGE_ERROR,
INTERNAL_ERROR
};
Service method:
Status SensorService::update() {
if (!driver_.isReady()) {
return Status::SENSOR_ERROR;
}
// read sensor
return Status::OK;
}
Application layer memutuskan transisi state.
4.2 HealthService Skeleton
class HealthService {
public:
void feedWatchdog();
void reportError(Status s);
Status currentError() const;
private:
Status last_error_ = Status::OK;
};
Watchdog hanya di-feed di satu domain.
4.3 Fail-Safe Pattern
if (health.currentError() != Status::OK) {
actuator.enterFailSafe();
}
Fail-safe eksplisit, bukan implicit.
4.4 Logging Abstraction
class ILogger {
public:
virtual void log(LogLevel level, const char* msg) = 0;
};
ControlTask tidak boleh blocking log.
5. Constraint & Embedded Impact
Reliability bukan sekadar βtambahan fiturβ. Ia harus selaras dengan constraint embedded yang sudah dikunci di Artikel 3β6.
5.1 RAM Impact
Statusenum sangat kecil (biasanya 4 byte).- Health metric disimpan dalam struktur ringkas.
- Logging queue harus bounded (fixed-size).
Jika logging menggunakan String atau buffer dinamis:
- Heap churn.
- Fragmentasi.
- Deadlock saat memory rendah.
Reliability model harus ringan dan deterministic.
5.2 Flash Impact
Menambahkan:
- Error enum
- HealthService
- Logging abstraction
Menambah flash sedikit.
Namun ini trade-off yang benar:
Auditability > sedikit penghematan flash.
5.3 Stack Impact
Tanpa exception:
- Stack depth lebih predictable.
- Tidak ada unwind chain tak terduga.
Logging via queue:
- Mengurangi call stack di ControlTask.
- Mencegah blocking di path kritikal.
5.4 Determinism Impact
Tanpa error model:
- Fungsi bisa gagal diam-diam.
- Control tetap berjalan dalam kondisi invalid.
Dengan explicit status:
- Error naik ke Application.
- Transisi state eksplisit.
- Fail-safe bisa aktif tepat waktu.
Reliability meningkatkan determinism, bukan menguranginya.
6. Failure Scenario
Reliability rule diuji di kondisi terburuk.
Scenario 1 β Sensor Gagal, Relay Tetap ON
Tanpa error propagation:
sensor.update();
Return value diabaikan.
Relay tetap ON.
Potensi:
- Overheat.
- Kerusakan mekanikal.
Dengan rule:
Status s = sensor.update();
if (s != Status::OK) {
health.reportError(s);
}
Application memicu fail-safe.
Relay kembali ke safe state.
Scenario 2 β Heap Hampir Habis
Tanpa health telemetry:
- TLS gagal.
- Publish gagal.
- Tidak ada peringatan awal.
Dengan health metric:
heap_min_freedikirim ke cloud.- Bisa dideteksi sebelum crash.
Proaktif, bukan reaktif.
Scenario 3 β Deadlock tapi Watchdog Tetap Di-Feed
Jika watchdog di-feed di banyak tempat:
esp_task_wdt_reset(); // tersebar - β
Deadlock di satu task tidak terdeteksi.
Dengan encapsulation:
- Hanya HealthService yang feed.
- Jika ControlTask hang β watchdog tidak di-feed.
- Reset terjadi sesuai desain.
Scenario 4 β Logging Blocking di ControlTask
Jika log langsung:
Serial.println("Error");
Saat USB slow atau buffer penuh:
- Blocking.
- Watchdog reset.
Dengan logging via queue:
- ControlTask hanya enqueue.
- Logging diproses di task lain.
7. Anti-Pattern
Daftar merah Artikel 7:
- β Exception handling
- β Silent catch-all
- β Mengabaikan return status
- β Fail-open relay
- β Watchdog feed tersebar
- β Logging blocking di ControlTask
- β Tidak ada health telemetry
Dampak:
- Tidak bisa audit root cause
- Uptime rendah
- Debug mahal
- Device gagal di lapangan tanpa jejak
8. Freeze Point
Setelah Artikel 7, keputusan berikut dianggap final:
- Error propagation eksplisit via
Status. - Exception dilarang.
- Watchdog encapsulated di
svc_HealthService. - Fail-safe state mandatory.
- Logging hanya via interface non-blocking.
- Health telemetry minimal wajib dikirim.
Reliability architecture tidak boleh berubah.
Artikel 8 hanya mengaudit dan menjaga, bukan menambah rule baru.
9. Engineering Checklist
Audit sebelum release produksi:
- Apakah semua fungsi kritikal return
Status? - Apakah ada return value yang diabaikan?
- Apakah relay punya default safe state?
- Apakah watchdog di-feed di banyak tempat?
- Apakah logging blocking?
- Apakah health metric masuk telemetry?
Jika satu saja βyaβ β melanggar Artikel 7.
10. Summary (5 Bullet Maksimal)
- Firmware rapi belum tentu reliable.
- Error harus eksplisit, bukan tersembunyi.
- Fail-safe bukan opsional.
- Watchdog harus punya owner.
- Observability adalah bagian dari arsitektur.
Catatan Penyusunan Artikel ini disusun sebagai materi edukasi dan referensi umum berdasarkan berbagai sumber pustaka, praktik lapangan, serta bantuan alat penulisan. Pembaca disarankan untuk melakukan verifikasi lanjutan dan penyesuaian sesuai dengan kondisi serta kebutuhan masing-masing sistem.