Cara menjalankan cron lebih dari sekali per menit menggunakan PHP

File config klasik untuk entri pekerjaan cron di sistem operasi Linux adalah sebagai berikut:

# ┌─────────────  (0 - 59)
# │ ┌─────────────  (0 - 23)
# │ │ ┌─────────────  (1 - 31)
# │ │ │ ┌─────────────  (1 - 12)
# │ │ │ │ ┌─────────────   (0 - 6)
# │ │ │ │ │
# * * * * * <  >

Lima parameter pertama menunjukkan waktu pelaksanaan tugas ini, dan keenam - perintah itu sendiri, yang harus dijalankan. Parameter waktu adalah: menit, jam, hari, bulan, dan hari dalam seminggu. Selain itu, semua angka harus direpresentasikan sebagai bilangan bulat atau dalam bentuk sintaksis khusus .

Akibatnya, interval minimum yang mungkin untuk meluncurkan perintah adalah satu menit sekali.

Untuk banyak tugas, eksekusi perintah diperlukan jauh lebih sering, misalnya, setiap 10 detik. Untuk beberapa tugas otomasi proses bisnis, penundaan maksimum yang diijinkan seringkali tidak lebih dari 1-1,5 detik.

Tentu saja, cron klasik tidak cocok untuk ini - perlu ditingkatkan.

Berikut ini adalah implementasi langkah demi langkah untuk menciptakan fungsionalitas tambahan (dalam PHP) ke cron klasik di Linux menggunakan perlindungan tambahan terhadap proses restart.

Pengaturan tugas dan pengaturan cron


Misalnya, kami akan menggunakan tugas berikut:

  1. Di ujung depan, pengguna dapat memulai pelaksanaan beberapa tugas kompleks dengan mengklik tombol "Jalankan";
  2. Bagian belakang setelah menulis baris baru ke database menginformasikan pengguna konfirmasi;
  3. Melalui cron, kami akan "melacak" tugas-tugas baru tersebut dan menyelesaikannya secepat mungkin sehingga pengguna tidak mendapatkan hasil dalam satu menit, tetapi segera *.

* Jika Anda menggunakan perintah peluncuran, hanya per menit, maka tugas akan dimulai ketika detik mencapai nol terdekat (awal menit baru). Oleh karena itu, dalam bentuk klasik, pengguna harus menunggu eksekusi dari 0 hingga 59 detik.

Jadi, cron akan dikonfigurasikan dalam bentuk maksimumnya, mis. satu menit sekali:

* * * * * /usr/bin/php -q /run.php > /dev/null 2>&1
#/usr/bin/php -    PHP   (      )
#/run.php -   PHP   
#> /dev/null 2>&1 - ,            run.php

Siklus tunggal


Pada awalnya, Anda harus memutuskan seberapa sering kami akan meminta tugas baru dalam database - tergantung pada ini, jumlah siklus dan tidur logis (fungsi sleep) akan berubah.

Dalam contoh saat ini, langkah 10 detik digunakan. Oleh karena itu, jumlah siklus adalah 60/10 = 6. Total, kode umum adalah sebagai berikut:

for ($cycle = 1; $cycle <= 6; $cycle++) { # 6 
    $all_tasks = get_all_tasks(); #     
    if ($all_tasks) { #    - 
        foreach($all_tasks as $one_task) { #     
            solve_one_task($one_task); #  
        }
    }
    sleep(10); #  ,  ""  10 
}

Klarifikasi : dalam contoh ini, langkah 10 detik digunakan, yang dapat memberikan interval eksekusi skrip minimum setiap 10 detik sekali. Karenanya, untuk eksekusi yang lebih sering, Anda harus mengubah jumlah siklus dan "waktu tidur".

Menghindari eksekusi tugas yang berulang


Dalam bentuk yang disajikan, ada satu ketidakpastian, yaitu, eksekusi tugas yang diulang jika sudah dimulai. Ini menjadi benar terutama jika tugas itu "sulit" dan memerlukan beberapa detik untuk mengimplementasikannya.

Ini menciptakan masalah eksekusi ulang:

  • Fungsi ini solve_one_task()sudah berjalan, tetapi belum menyelesaikan tugasnya;
  • Oleh karena itu, dalam database tugas masih ditandai sebagai tidak terpenuhi;
  • Siklus berikutnya akan mendapatkan tugas ini lagi dan menjalankan fungsinya solve_one_task()lagi, dengan tugas yang sama.

Tentu saja, ini dapat diselesaikan, misalnya, dengan mengubah beberapa status dalam database untuk tugas ini.

Tetapi kami tidak akan memuat database: berdasarkan pengujian saya, MYSQL dapat menerima permintaan, tetapi tidak segera memprosesnya. Perbedaan bahkan 0,5 detik dapat menyebabkan eksekusi berulang - yang pasti tidak cocok.

Juga dalam hal ini kita hanya berbicara tentang status tugas, jadi lebih baik menggunakan sistem file server.

Model verifikasi dasar dibangun menggunakan flock- fungsi yang mengatur dan membuka kunci file.

Dalam eksekusi PHP, fungsinya dapat direpresentasikan sebagai berikut:

$lock_file_abs = 'file'; #  
$fp = fopen($lock_file_abs,"w+"); #   
if (flock($fp, LOCK_EX | LOCK_NB)) { #,    
    solve_one_task($one_task); #  
    flock($fp, LOCK_UN); #   ,     
}
else {
    #,   , ..       
}
fclose($fp); #   
unlink($lock_file_abs); # ,   

Hasil


Pandangan umum dari seluruh siklus adalah sebagai berikut:

for ($cycle = 1; $cycle <= 6; $cycle++) {
    $all_tasks = get_all_tasks();
    if ($all_tasks) {
        foreach($all_tasks as $one_task) {
            $lock_file_abs = __DIR__.'/locks/run_'.$one_task['id'];
            $fp = fopen($lock_file_abs,"w+");
            if (flock($fp, LOCK_EX | LOCK_NB)) {
                solve_one_task($one_task);
                flock($fp, LOCK_UN);
            }
            else {
                #    
            }
            fclose($fp);
            unlink($lock_file_abs);
        }
    }
    sleep(10);
}

Dengan demikian, algoritma semacam itu memungkinkan Anda untuk memulai pelaksanaan siklus pemrosesan tugas dan tidak khawatir bahwa tugas akan diproses lebih dari sekali.

Dan sekarang cukup menjalankan kode ini melalui cron setiap menit, dan pada gilirannya, akan menjalankan siklus yang lebih kecil yang sudah ada di dalam dirinya sendiri.

All Articles