PHP Academy · Pelajaran

Membina Aliran Kerja Dipacu Peristiwa

Selaraskan perkhidmatan melalui peristiwa dan keidempotenan.

Pelajaran 4 daripada 413 langkah

Membina Aliran Kerja Dipacu Peristiwa ialah pelajaran PHP Academy percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran PHP Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus PHP Academy merangkumi sejumlah 4 pelajaran.

Aliran Kerja Dipacu Peristiwa

Satu mesej mudah. Aliran kerja — "pesanan dibuat → tempah stok → caj kad → hantar → maklumkan" yang merentasi beberapa perkhidmatan — ialah keadaan yang menunjukkan manfaat reka bentuk dipacu peristiwa, dan juga keadaan yang menyusahkan anda jika dilaksanakan secara naif.

Pelajaran ini merangkumi koreografi berbanding orkestrasi, corak peti keluar untuk penerbitan atomik, saga untuk pemulangan teragih dan keidempotenan yang menyatukan semuanya.

Koreografi berbanding Orkestrasi

Dua cara untuk menyelaraskan aliran berbilang langkah:

  • Koreografi — setiap perkhidmatan bertindak balas terhadap peristiwa dan menghasilkan peristiwanya sendiri; tiada pusat kawalan. Gandingan longgar, tetapi aliran keseluruhan tersirat dan sukar dijejaki.
  • Orkestrasi — penyelaras pusat memberitahu setiap perkhidmatan perkara yang perlu dilakukan seterusnya. Jelas dan boleh diperhatikan, tetapi penyelaras ialah titik gandingan.

Panduan umum: gunakan koreografi untuk pengagihan mudah kepada banyak penerima, dan orkestrasi apabila aliran mempunyai banyak langkah tersusun serta memerlukan keadaan yang jelas.

Peristiwa berbanding Arahan

Namakan mesej dengan sengaja:

  • Peristiwa menyatakan fakta yang telah berlaku: OrderPlaced. Penerbit tidak mempedulikan siapa yang mendengar.
  • Arahan meminta tindakan akan datang daripada pengendali tertentu: ChargeCard.

Peristiwa memacu koreografi; arahan memacu orkestrasi. Mencampurkan istilah ("peristiwa" yang sebenarnya mengharapkan satu pengendali) ialah punca biasa gandingan tersembunyi.

<?php
final class OrderPlaced {
    public function __construct(
        public readonly string $orderId,
        public readonly string $customerId,
        public readonly int $amountCents,
        public readonly string $occurredAt,
    ) {}
}

$e = new OrderPlaced('o-42', 'c-7', 1990, gmdate('c'));
echo json_encode($e), "\n";

Masalah Penulisan Berganda

Ralat klasik: pengendali mengemas kini pangkalan data dan menerbitkan mesej sebagai dua operasi berasingan. Jika proses terhenti di antaranya, anda mendapat ketidakselarasan — baris berubah tetapi tiada peristiwa dihantar, atau begitu juga sebaliknya.

<?php
// BROKEN: not atomic. A crash between the two lines corrupts state.
function placeOrder(PDO $db, $broker, array $o): void {
    $db->prepare('INSERT INTO orders ...')->execute($o);
    // <-- crash here = row exists but no event ever published
    $broker->publish('OrderPlaced', json_encode($o));
}

Peti Keluar Transaksi

Penyelesaiannya ialah corak peti keluar: dalam transaksi pangkalan data yang sama yang mengubah data anda, masukkan peristiwa ke dalam jadual outbox. Proses geganti yang berasingan membaca baris yang belum diterbitkan dan menghantarnya kepada pelayan perantara. Satu pengesahan atomik, tanpa penulisan berganda.

<?php
function placeOrder(PDO $db, array $o): void {
    $db->beginTransaction();
    $db->prepare('INSERT INTO orders (id, total) VALUES (?, ?)')
       ->execute([$o['id'], $o['total']]);
    // Same transaction -> atomic with the business write
    $db->prepare('INSERT INTO outbox (id, type, payload) VALUES (?, ?, ?)')
       ->execute([bin2hex(random_bytes(8)), 'OrderPlaced', json_encode($o)]);
    $db->commit();
}

Geganti (Pengeluar)

Pekerja meninjau peti keluar (atau mengikuti catatan perubahan pangkalan data melalui CDC), menerbitkan setiap baris, kemudian menandakannya sebagai telah dihantar. Oleh sebab geganti boleh ranap selepas penerbitan tetapi sebelum penandaan, geganti itu sendiri menggunakan penghantaran sekurang-kurangnya sekali — dan hal ini tidak mengapa kerana pengguna bersifat idempoten.

<?php
function relayOutbox(PDO $db, $broker): void {
    $rows = $db->query(
        'SELECT id, type, payload FROM outbox
         WHERE published_at IS NULL ORDER BY created_at LIMIT 100'
    )->fetchAll(PDO::FETCH_ASSOC);

    foreach ($rows as $r) {
        $broker->publish($r['type'], $r['payload'], messageId: $r['id']);
        $db->prepare('UPDATE outbox SET published_at = now() WHERE id = ?')
           ->execute([$r['id']]);
    }
}

Pengguna Idempoten (Sekali Lagi)

Oleh sebab geganti dan pelayan perantara kedua-duanya menggunakan penghantaran sekurang-kurangnya sekali, pengendali hiliran akan melihat pendua. Setiap pengguna merekodkan ID mesej yang telah diprosesnya dan menghentikan pemprosesan ulangan — get deduplikasi yang sama seperti yang anda pelajari sebelum ini, kini digunakan bagi setiap perkhidmatan.

<?php
function onOrderPlaced(PDO $db, string $messageId, array $data): void {
    $db->beginTransaction();
    try {
        $db->prepare('INSERT INTO inbox (message_id) VALUES (?)')
           ->execute([$messageId]); // unique index = dedup
    } catch (PDOException $e) {
        $db->rollBack();
        return; // already handled this message
    }
    reserveStock($data['orderId']);
    $db->commit();
}
function reserveStock(string $id): void {}

Saga: Pemulangan Teragih

Anda tidak boleh membuka satu transaksi ACID merentasi perkhidmatan. Saga memodelkan aliran jangka panjang sebagai urutan transaksi setempat, setiap satunya dengan tindakan pampasan yang membatalkannya. Jika langkah 3 gagal, jalankan pampasan untuk langkah 2 dan 1 dalam susunan terbalik.

Contoh: pembayaran gagal selepas stok ditempah → keluarkan ReleaseStock sebagai pampasan. Tiada pemulangan automatik — anda perlu mereka bentuk pembatalan bagi setiap langkah.

Saga yang Diorkestrakan

Penyelaras memacu saga: ia bergerak ke hadapan apabila berjaya dan menghantar pampasan apabila gagal. Simpan keadaan saga supaya ranap boleh disambung semula.

<?php
function handleStepResult(array $saga, string $step, bool $ok, $bus): array {
    if ($ok) {
        $next = ['reserveStock' => 'chargeCard', 'chargeCard' => 'ship'][$step] ?? null;
        if ($next) { $bus->send($next, $saga['orderId']); $saga['state'] = $next; }
        else { $saga['state'] = 'completed'; }
    } else {
        // Run compensations in reverse for whatever already succeeded
        foreach (array_reverse($saga['done']) as $s) {
            $bus->send('compensate.' . $s, $saga['orderId']);
        }
        $saga['state'] = 'compensating';
    }
    return $saga;
}

Had Masa dalam Aliran Panjang

Langkah saga mungkin tidak pernah memberikan respons — perkhidmatan pembayaran tidak tersedia atau kelulusan manusia tidak kunjung tiba. Tanpa had masa, saga akan tergantung selama-lamanya sambil mengekalkan tempahan. Simpan tarikh akhir bagi setiap langkah; penjadual mengimbas saga yang melepasi tarikh akhir dan mencetuskan laluan kegagalan/pampasan.

<?php
function reapTimedOutSagas(PDO $db, $bus): void {
    $rows = $db->query(
        "SELECT order_id, state FROM sagas
         WHERE state NOT IN ('completed','compensating')
           AND deadline_at < now()"
    )->fetchAll(PDO::FETCH_ASSOC);

    foreach ($rows as $r) {
        echo "Saga {$r['order_id']} timed out at step {$r['state']}\n";
        $bus->send('saga.compensate', $r['order_id']); // trigger rollback
    }
}

Pengurusan Versi & Kebolehcerapan

Aliran kerja boleh berfungsi selama bertahun-tahun; peristiwa mesti berkembang dengan selamat:

  • Tambahkan version (atau skema) pada setiap peristiwa; pengguna bertolak ansur dengan medan baharu yang tidak dikenali dan tidak pernah menganggap sesuatu medan pasti wujud.
  • Utamakan perubahan tambahan; jangan sesekali mengubah maksud medan sedia ada.
  • Sebarkan ID korelasi melalui setiap mesej supaya anda boleh menjejaki satu transaksi perniagaan merentasi semua perkhidmatan dalam log dan penjejakan anda.

Tanpa ID korelasi, penyahpepijatan aliran koreografi merentasi lima perkhidmatan hampir mustahil.

<?php
$envelope = [
    'type'          => 'OrderPlaced',
    'version'       => 2,
    'correlationId' => $incoming['correlationId'] ?? bin2hex(random_bytes(8)),
    'occurredAt'    => gmdate('c'),
    'data'          => ['orderId' => 'o-42'],
];
echo json_encode($envelope, JSON_PRETTY_PRINT), "\n";

Semakan Pantas

Mengelakkan masalah penulisan berganda.

Rumusan

Anda kini boleh mereka bentuk aliran kerja dipacu peristiwa yang boleh dipercayai:

  • Pilih koreografi (peristiwa) atau orkestrasi (arahan) berdasarkan kerumitan setiap aliran.
  • Selesaikan penulisan berganda dengan peti keluar transaksi + penyampai.
  • Jadikan setiap pengguna idempoten melalui kunci peti masuk/nyahganda.
  • Gunakan saga dengan tindakan pampasan untuk pengembalian teragih.
  • Versikan peristiwa secara tambahan dan sertakan ID korelasi untuk kebolehjejakan.

Corak ini menukarkan mesej yang berselerak menjadi proses perniagaan yang boleh dipercayai dan boleh dicerap.

Percuma untuk bermula

Pelajari PHP dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
49
Pelajaran
195

Soalan Lazim

Adakah pelajaran “Membina Aliran Kerja Dipacu Peristiwa” percuma?

Ya — teks penuh “Membina Aliran Kerja Dipacu Peristiwa” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus PHP Academy, tingkat taraf kepada CoddyKit PRO. Kursus PHP Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Membina Aliran Kerja Dipacu Peristiwa”?

Selaraskan perkhidmatan melalui peristiwa dan keidempotenan. Anda berlatih PHP Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan PHP Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran PHP Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.

Berapa lamakah pelajaran “Membina Aliran Kerja Dipacu Peristiwa” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran PHP Academy ini?

Ya. Setiap pelajaran PHP Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Mengapa Pemesejan Tak Segerak
  2. Bekerja dengan RabbitMQ dalam PHP
  3. Apache Kafka dengan PHP
  4. Membina Aliran Kerja Dipacu Peristiwa
← Kembali ke PHP Academy