0Pricing
Scala for Backend Engineering & Functional Programming · Pelajaran

Supervisi dan Toleransi Kesalahan

Jelajahi strategi supervisi Akka untuk membuat sistem tangguh yang dapat pulih dari kegagalan dengan baik.

Supervisi dan Toleransi Kesalahan adalah pelajaran Scala for Backend Engineering & Functional Programming gratis di CoddyKit. Ini adalah pelajaran 3 dari 3. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Scala for Backend Engineering & Functional Programming, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Scala for Backend Engineering & Functional Programming mencakup 3 pelajaran total.

Membangun Sistem yang Tangguh

Dalam aplikasi konkuren, berbagai hal dapat mengalami masalah. Aktor mungkin mengalami kerusakan, panggilan jaringan mungkin gagal, atau basis data mungkin tidak dapat dijangkau.

Toleransi kesalahan adalah kemampuan sistem untuk terus beroperasi dengan benar meskipun sebagian komponennya mengalami kegagalan. Akka menyediakan mekanisme yang kuat untuk mencapainya.

Supervisi Induk-Anak

Aktor Akka diatur dalam hierarki, mirip seperti silsilah keluarga. Saat sebuah aktor membuat aktor lain, aktor tersebut menjadi induknya.

  • Induk bertanggung jawab mengawasi anak-anaknya.
  • Jika aktor anak gagal, induknya menerima pemberitahuan.
  • Induk kemudian menentukan cara menangani kegagalan anak tersebut. Hal ini disebut strategi supervisi.

Menentukan Tindakan saat Gagal

Saat sebuah aktor gagal, induknya dapat mengeluarkan salah satu dari empat arahan:

  • Resume: Aktor melanjutkan pemrosesan pesan dengan mengabaikan kegagalan.
  • Restart: Aktor dihentikan, dibuat ulang, lalu melanjutkan pemrosesan. Status internalnya diatur ulang.
  • Stop: Aktor dihentikan secara permanen.
  • Escalate: Kegagalan diteruskan kepada supervisor induknya (kakek aktor tersebut).

Strategi OneForOne

OneForOneStrategy adalah strategi supervisi yang umum digunakan. Artinya, arahan hanya berlaku untuk aktor anak yang mengalami kegagalan.

Misalnya, jika salah satu aktor anak mengalami kerusakan, induknya dapat memilih untuk memulai ulang hanya anak tersebut, sementara anak-anak lainnya tetap tidak terpengaruh.

OneForOne dalam Praktik

Mari lihat OneForOneStrategy. Kita akan membuat induk yang memulai ulang anak saat terjadi ArithmeticException, tetapi menghentikannya saat terjadi pengecualian lain.

import akka.actor._
import akka.actor.SupervisorStrategy._
import scala.concurrent.duration._

object OneForOneExample extends App {
  class Child extends Actor {
    override def preStart(): Unit = {
      println(s"Child ${self.path.name}: Started!")
    }
    override def postStop(): Unit = {
      println(s"Child ${self.path.name}: Stopped!")
    }
    override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
      println(s"Child ${self.path.name}: Pre-restart due to ${reason.getMessage}")
    }
    override def postRestart(reason: Throwable): Unit = {
      println(s"Child ${self.path.name}: Post-restart!")
    }
    def receive = {
      case "divideByZero" => throw new ArithmeticException("Oops, dividing by zero!")
      case "nullPointer"  => throw new NullPointerException("Something is null!")
      case msg            => println(s"Child ${self.path.name}: Received $msg")
    }
  }

  class Parent extends Actor {
    override val supervisorStrategy: SupervisorStrategy =
      OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1.minute) {
        case _: ArithmeticException => Restart
        case _: NullPointerException => Stop
        case _                      => Escalate
      }

    val child = context.actorOf(Props[Child], "myChild")

    def receive = {
      case msg => child ! msg
    }
  }

  val system = ActorSystem("OneForOneSystem")
  val parent = system.actorOf(Props[Parent], "myParent")

  parent ! "Hello"
  parent ! "divideByZero" // Should cause a restart
  Thread.sleep(100)
  parent ! "Hello again"
  Thread.sleep(1000) // Give time for restart to complete

  parent ! "nullPointer"  // Should cause a stop
  Thread.sleep(100)
  parent ! "Hello after null" // This message will not be processed by child
  Thread.sleep(2000)

  system.terminate()
}

Mengamati OneForOne

Apakah Anda menjalankan kode sebelumnya? Berikut yang terjadi:

  • Saat "divideByZero" dikirim, anak melempar ArithmeticException. Induk menerapkan Restart. Anda melihat log "Pra-pemulaan ulang" dan "Pasca-pemulaan ulang".
  • Anak kemudian memproses "Hello again".
  • Saat "nullPointer" dikirim, anak melempar NullPointerException. Induk menerapkan Stop. Anak dihentikan.
  • "Hello after null" dikirim, tetapi anak sudah dihentikan dan tidak dapat memprosesnya.

Strategi AllForOne

Terkadang, kegagalan pada satu anak berarti semua anak saudaranya juga mungkin terdampak atau tidak dapat berfungsi dengan benar.

AllForOneStrategy menerapkan arahan yang sama kepada semua anak supervisor, bukan hanya anak yang mengalami kegagalan. Jika satu anak gagal, semua anak terdampak oleh arahan yang dipilih.

AllForOne dalam Praktik

Mari ubah induk kita agar menggunakan AllForOneStrategy. Perhatikan bagaimana kegagalan satu anak memengaruhi saudaranya.

import akka.actor._
import akka.actor.SupervisorStrategy._
import scala.concurrent.duration._

object AllForOneExample extends App {
  class Child extends Actor {
    override def preStart(): Unit = {
      println(s"Child ${self.path.name}: Started!")
    }
    override def postStop(): Unit = {
      println(s"Child ${self.path.name}: Stopped!")
    }
    override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
      println(s"Child ${self.path.name}: Pre-restart due to ${reason.getMessage}")
    }
    override def postRestart(reason: Throwable): Unit = {
      println(s"Child ${self.path.name}: Post-restart!")
    }
    def receive = {
      case "fail" => throw new RuntimeException("Child failed!")
      case msg    => println(s"Child ${self.path.name}: Received $msg")
    }
  }

  class Parent extends Actor {
    override val supervisorStrategy: SupervisorStrategy =
      AllForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1.minute) {
        case _: RuntimeException => Restart
        case _                   => Escalate
      }

    val childA = context.actorOf(Props[Child], "childA")
    val childB = context.actorOf(Props[Child], "childB")

    def receive = {
      case "failA" => childA ! "fail"
      case "msgB"  => childB ! "Hello from B"
      case msg     => println(s"Parent received: $msg")
    }
  }

  val system = ActorSystem("AllForOneSystem")
  val parent = system.actorOf(Props[Parent], "myParent")

  parent ! "msgB" // Child B receives a message
  Thread.sleep(100)

  parent ! "failA" // Child A fails, causing all children to restart
  Thread.sleep(1000)

  parent ! "msgB" // Child B (restarted) receives another message
  Thread.sleep(2000)

  system.terminate()
}

Menyesuaikan Penentu Tindakan

Anda dapat membuat logika supervisi yang sangat disesuaikan menggunakan fungsi penentu. Fungsi ini menerima Throwable (pengecualian) dan mengembalikan Directive.

Dengan demikian, Anda dapat menerapkan aturan kompleks berdasarkan jenis pengecualian, pesan yang menyebabkannya, atau bahkan status supervisor.

Supervisi Lanjutan

Berikut cara mendefinisikan penentu khusus dalam strategi supervisor untuk mendapatkan kendali yang lebih terperinci.

import akka.actor._
import akka.actor.SupervisorStrategy._
import scala.concurrent.duration._

object CustomDeciderExample extends App {
  class Worker extends Actor {
    def receive = {
      case "criticalError" => throw new IllegalStateException("Critical state!")
      case "minorError"    => throw new IllegalArgumentException("Bad input!")
      case msg             => println(s"Worker: Received $msg")
    }
  }

  class Supervisor extends Actor {
    override val supervisorStrategy: SupervisorStrategy =
      OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 10.seconds) {
        case _: IllegalArgumentException => Resume // Minor error, just resume
        case _: IllegalStateException    => Restart // Critical, restart
        case _: Exception                => Stop    // Unknown, stop
        case _                           => Escalate // Others, escalate
      }

    val worker = context.actorOf(Props[Worker], "myWorker")

    def receive = {
      case msg => worker ! msg
    }
  }

  val system = ActorSystem("CustomDeciderSystem")
  val supervisor = system.actorOf(Props[Supervisor], "mySupervisor")

  supervisor ! "Hello"
  supervisor ! "minorError" // Should Resume
  Thread.sleep(100)
  supervisor ! "Hello again" // Worker should still be active
  Thread.sleep(500)

  supervisor ! "criticalError" // Should Restart
  Thread.sleep(100)
  supervisor ! "After critical" // Worker should be restarted
  Thread.sleep(1500)

  system.terminate()
}

Uji Pengetahuan Anda

Perhatikan aktor induk yang mengawasi dua aktor anak, childA dan childB. Induk tersebut menggunakan AllForOneStrategy dengan arahan Restart untuk semua pengecualian.

Jika childA melempar pengecualian, apa yang akan terjadi?

Rangkuman: Toleransi Kesalahan

Kerja bagus! Dalam pelajaran ini, Anda telah mempelajari mekanisme supervisi Akka yang kuat:

  • Hierarki Supervisi: Induk mengawasi anak.
  • Arahan: Resume, Restart, Stop, Escalate.
  • OneForOneStrategy: Menerapkan arahan hanya kepada anak yang gagal.
  • AllForOneStrategy: Menerapkan arahan kepada semua anak.
  • Penentu Khusus: Untuk mengendalikan penanganan kegagalan secara lebih terperinci.

Perangkat ini sangat penting untuk membangun aplikasi konkuren yang tangguh dan tahan terhadap gangguan dengan Aktor Akka!

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Supervisi dan Toleransi Kesalahan” gratis?

Ya — teks lengkap “Supervisi dan Toleransi Kesalahan” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Scala for Backend Engineering & Functional Programming, upgrade ke CoddyKit PRO. Kursus Scala for Backend Engineering & Functional Programming mencakup 3 pelajaran total.

Apa yang akan aku pelajari di “Supervisi dan Toleransi Kesalahan”?

Jelajahi strategi supervisi Akka untuk membuat sistem tangguh yang dapat pulih dari kegagalan dengan baik. Kamu berlatih Scala for Backend Engineering & Functional Programming dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Scala for Backend Engineering & Functional Programming?

Tidak diperlukan pengalaman sebelumnya. Scala for Backend Engineering & Functional Programming di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 3.

Berapa lama pelajaran “Supervisi dan Toleransi Kesalahan” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Scala for Backend Engineering & Functional Programming ini?

Ya. Setiap pelajaran Scala for Backend Engineering & Functional Programming menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Dasar-Dasar Model Aktor Akka
  2. Merancang Sistem Aktor
  3. Supervisi dan Toleransi Kesalahan
← Kembali ke Scala for Backend Engineering & Functional Programming