Rumah  >  Artikel  >  rangka kerja php  >  Menggunakan peristiwa Pemerhati dalam Laravel menyebabkan masalah pengecualian baris gilir Redis

Menggunakan peristiwa Pemerhati dalam Laravel menyebabkan masalah pengecualian baris gilir Redis

藏色散人
藏色散人ke hadapan
2021-12-03 09:33:482316semak imbas

Lajur tutorial Laravel berikut akan berkongsi dengan anda rekod tentang pengecualian baris gilir Redis yang disebabkan oleh Laravel Observer, saya harap ia akan membantu semua orang!

1. Logik perniagaan

Selepas mencipta model baharu, gunakan acara model Observer Created untuk menolak ke dalam baris gilir penghantaran SMS tak segerak

AppHttpControllersUsersController

    public function store(User $user)
    {
        \DB::beginTransaction();

        try{
            $input = request()->validated();
            $user->fill($input);
            $user->save();
            //do something......
            //其他数据表操作

            \DB::commit();
        } catch ($e \Exception) {
            \DB::rollBack();
        }

    }

AppObserversUserObserver

class UserObserver{
    public function created (User $user)
    {
        dispatch(new SmsQueue($user));
    }}

2 Keabnormalan ditemui

Jabatan perniagaan melaporkan bahawa kadangkala pengguna tidak dapat menerima pemberitahuan SMS. , jadi saya menyemak Log mendapati terdapat ralat dan pengecualian sekali-sekala: Tiada hasil pertanyaan untuk model [AppModelsUser]. selepas mencipta model..., jadi saya membetulkan Kod perniagaan telah diperiksa dengan teliti dan meneka bahawa ia sepatutnya dipengaruhi oleh transaksi.

Sahkan sangkaan:

Sudah tentu, selepas menunggu selama tiga saat, pengecualian baris gilir penyerahan 100% dicetuskan.
    public function store(User $user)
    {
        \DB::beginTransaction();

        try{
            $input = request()->validated();
            $user->fill($input);
            $user->save();
            //do something......
            //其他数据表操作

            sleep(3); //三秒之后再提交事务            
            \DB::commit();
        } catch ($e \Exception) {
            \DB::rollBack();
        }

    }

3. Analisis sebab

    $user->save() Kaedah ini akan mencetuskan penjadual jika data berjaya dibuat model acara satu persatu.
  • Tolak model ke baris gilir dalam acara dan proses baris gilir menggunakan data dalam baris gilir secara berterusan.
  • Dalam kebanyakan kes, jika melakukan sesuatu kelajuan pemprosesan adalah normal, proses giliran akan berjalan seperti biasa.
  • Jika terdapat kelewatan sekali-sekala semasa fasa melakukan sesuatu, menyebabkan transaksi dilakukan tetapi baris gilir telah mula menggunakan model baharu oleh itu, ralat di atas berlaku;
  • Kemudian apabila saya mencari rekod Isu Github, saya mendapati bahawa isu ini telah dibangkitkan dalam Isu pada tahun 2015, dan dalam Laravel 8.X akhirnya menambah sokongan untuk acara model transaksi Sokongan; learnku.com/docs/laravel/8.x/eloqu... , tetapi nampaknya tiada arahan berkaitan ditemui dalam dokumentasi komuniti~

Memandangkan versi saya ialah 6.x, saya tidak boleh menggunakan yang baharu ini ciri [ Menangis]~~

4 Menyelesaikan pengecualian

1 Ubah suai tahap pengasingan transaksi MySQL (tidak disyorkan) Ini melibatkan tahap pengasingan transaksi MySQL Tahap pengasingan lalai bagi enjin InnoDB ialah BACA BERULANG Perbezaan antara setiap peringkat boleh didapati dalam dokumentasi rasmi.

Menukar tahap pengasingan kepada READ UNCOMMITTED boleh menyelesaikan masalah ini, tetapi untuk mengelakkan masalah yang lebih besar, saya menasihati anda untuk tidak menggunakan kaedah ini~

2 pemantauan acara Semak kod sumber untuk mengetahui bahawa selepas transaksi selesai, acara yang sepadan akan dipanggil, jadi anda hanya perlu menambah pemantauan acara.

Menggunakan peristiwa Pemerhati dalam Laravel menyebabkan masalah pengecualian baris gilir Redis

    Tambah kelas baharu
  1. AppHandlersTransactionHandler

    class TransactionHandler{
        public array $handlers;
    
        public function __construct()
        {
            $this->handlers = [];
        }
    
        public function add(\Closure $handler)
        {
            $this->handlers[] = $handler;
        }
    
        public function run()
        {
            foreach ($this->handlers as $handler) {
                $handler();
            }
            $this->handlers = [];
        }}
  2. Buat fungsi tambahan
  3. app/helpers.php

    if (! function_exists('after_transaction')) {
        /*
         * 事务结束之后再进行操作
         * */
        function after_transaction(Closure $job)
        {
            app()->singletonIf(\App\Handlers\TransactionHandler::class, function (){
                return new \App\Handlers\TransactionHandler();
            });
            app(\App\Handlers\TransactionHandler::class)->add($job);
        }}
  4. Buat pendengar
  5. AppListenersTransactionListener

    namespace App\Listeners;use App\Handlers\TransactionHandler;class TransactionListener{
        public function handle()
        {
            app(TransactionHandler::class)->run();
        }}
  6. Ikat pendengar
  7. AppProvidersEventServiceProvider

    namespace App\Providers;use App\Listeners\TransactionListener;use Illuminate\Database\Events\TransactionCommitted;use Illuminate\Database\Events\TransactionRolledBack;use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;;class EventServiceProvider extends ServiceProvider{
        /**
         * The event listener mappings for the application.
         *
         * @var array
         */
        protected $listen = [
            TransactionCommitted::class => [
                TransactionListener::class
            ],
            TransactionRolledBack::class => [
                TransactionListener::class
            ]
        ];}
  8. Tukar kaedah panggilan
  9. AppObserversUserObserver

OK, penyelesaian yang elegan telah selesai~~
class UserObserver{
    public function created (User $user)
    {
        after_transaction(function() use ($user) {
            dispatch(new SmsQueue($user));
        });
    }}

Cadangan berkaitan:

Video Five Laravel terkini tutorial

Atas ialah kandungan terperinci Menggunakan peristiwa Pemerhati dalam Laravel menyebabkan masalah pengecualian baris gilir Redis. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:learnku.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam