Cron job
Area: operasional. Pekerja latar belakang lintas modul, bukan satu modul. Mereka harus dijadwalkan di server lewat crontab sistem. Mereka ada di direktori top-level cron/ sebagai skrip PHP mandiri yang dijalankan daemon cron OS, tidak pernah dari UI aplikasi.
Cara halaman ini diverifikasi
Daftar direktori dibaca di branch produksi masing-masing big five pada 2026-09-16. Job Multiple Sign Off dibaca di master pada commit INA01-866 e230a25be dan c63dd6658, yang saat halaman ini ditulis masih lokal dan belum ada di origin/main. Job lain dibaca di master pada 2026-09-06.
Beberapa job memanggil endpoint HTTP di dalam aplikasi dengan cURL, jadi base URL aplikasi ($inweb_baseurl, baris baseurl di inweb_config) harus bisa dijangkau dari server itu sendiri dan TLS harus berfungsi. Panggilan ini menonaktifkan SSL_VERIFYPEER.
Crontab produksi minimal
README.md master memasang dua entri pertama. Job Multiple Sign Off diperlukan di mana pun pengguna men-sign off beberapa routing sekaligus. Dua terakhir adalah job notifikasi yang dijaga config.
# setiap menit — kirim antrean email keluar (SMTP lewat PHPMailer)
* * * * * php /path/to/app/cron/inact_mailgun_curl.php >> /dev/null 2>&1
# setiap menit — antrean submission procurement
* * * * * php /path/to/app/cron/cron_submit_queue.php >> /dev/null 2>&1
# setiap menit — selesaikan Multiple Sign Off (dokumen approved, transmittal, publish library)
* * * * * php /path/to/app/cron/cron_multiple_signoff_v2.php >> /var/log/inact_multisignoff.log 2>&1
# setiap jam — digest routing (hanya bertindak saat enable_routing_notif_digest=1)
0 * * * * php /path/to/app/cron/inact_routing_digest.php
# harian — notifikasi routing overdue / akan jatuh tempo
0 7 * * * php /path/to/app/cron/cron_overdue_mail.phpSesuaikan binary PHP dan path per environment dan arahkan output ke log supaya kegagalan terlihat. Aktifkan cron retention dan digest hanya kalau feature flag-nya menyala. Tidak ada baris crontab yang dipasang oleh deploy: skrip deploy/ master dan .github/workflows/deploy.yml tidak menyentuh cron. Setiap baris di atas adalah langkah manual di setiap server. Crontab produksi milik klien, lihat masing-masing halaman instance.
Job-job-nya
1. inact_mailgun_curl.php memanggil inact_mailgun2.php: antrean email keluar, setiap menit
Semua email keluar diantrekan ke ts_email; tidak ada yang dikirim sinkron. Pembungkus memanggil inact_mailgun2.php, yang memilih baris tertunda (ts_email WHERE email_sent='n', yang terlama dulu, ukuran batch dari EMAIL_TOTAL_PER_BATCH), menandainya 'q', dan mengirim masing-masing lewat SMTP (PHPMailer) memakai setting $inweb_smtp_*. Saat berhasil email_sent='y' plus stempel waktu kirim; saat gagal 'e'. Menghormati kuota harian (EMAIL_QUOTA_PER_DAY, -1 = tanpa batas). Meski namanya "mailgun", pengirimannya lewat SMTP.
- Tabel:
ts_email(email_sent:n, laluq, laluyataue). - Config: key
.envEMAIL_QUOTA_PER_DAY(default-1) danEMAIL_TOTAL_PER_BATCH(default10), dibaca dengan$_ENV[...] ?? defaultdiinact_mailgun2.php. Keduanya tidak ada di file env contoh; set hanya untuk mengubah default. - Kalau tidak berjalan: tidak ada email yang pernah terkirim. Setiap notifikasi menumpuk tak terkirim.
Pembungkus menargetkan inact_mailgun2.php di kelima fork.
2. cron_multiple_signoff_v2.php: menyelesaikan Multiple Sign Off, setiap menit
Multiple Sign Off mencatat semua sign off sekaligus, lalu mengantrekan pekerjaan yang lambat di ts_multiple_signoff_list, satu baris per performer yang sign off (rout_id, map_id). Job ini mengerjakan pekerjaan lambat itu. Ini versi master sejak INA01-866; cron_multiple_signoff.php, cron_create_routing_slip.php dan getPDFMultipleSignoffCron.php yang lama sudah dihapus dari master.
| Performer yang sign off | Yang dijalankan job | Hasil |
|---|---|---|
| Di bagian Document Controller dari routing (D - Transmit) | publishTransmitSignOff() | Record Document Library, Transmittal keluar saat issued status external dan enable_transmittal = 1, folder library. Satu transaksi DB. |
| Selain itu (A - Approval, C / S yang me-reject, I - Information terakhir) | finishApprovalSignOff() | curl ke getPDFAfterApprove.php (dokumen _R), Transmittal return saat external dan enable_transmittal = 1, folder library setelah sign off yang approved |
- Batch: 10 baris,
multi_idterlama dulu, hanyamulti_status = 'n',cron_ongoing'n'atau NULL, danmap_idtidak NULL. - Klaim: tiap baris diset
cron_ongoing = 'y'sebelum pekerjaannya dimulai. Berhasil mengesetmulti_status = 'y',cron_ongoing = 'n'. Exception atau PHPErrorapa pun mengeset keduanya kembali ke'n', jadi baris dicoba lagi menit berikutnya. Tidak ada batas percobaan ulang. - Setiap baris diklaim sendiri, dengan satu UPDATE bersyarat yang hanya cocok untuk baris yang masih bebas. Dua eksekusi yang tumpang tindih tidak pernah mengambil baris yang sama, jadi tidak perlu lock file atau
flock. Baris yang dilewati mencetakqueue row 12: taken by another run, skipped. - Setiap baris dijalankan atas nama performer yang sign off (
getSignOffPerformer()), jadi author dokumen dan log menunjukkan orang itu, bukan user sistem. - Flag: publish butuh
enable_autopublish = 1; dokumen_Runtuk A juga butuh flag itu. I - Information selalu membangun dokumennya. - Kalau tidak berjalan: sign off tercatat dan routing tertutup, tetapi dokumen
_Rapproved, Transmittal dan record Document Library tidak muncul. Baris menumpuk dimulti_status = 'n'. - Detail: Multiple Sign Off.
3. inact_routing_digest.php: digest routing, setiap jam, dijaga flag
Saat enable_routing_notif_digest='1', routing_notif_digest_hour tidak kosong, dan jam saat ini ada di CSV itu, ia mengelompokkan baris ts_map_routing_to yang masih terbuka per project dan penerima dan mengirim satu email digest gabungan per pengguna, diantrekan lewat ts_email.
- Config:
enable_routing_notif_digest,routing_notif_digest_hour, lihat inweb_config. - Kalau flag-nya mati: langsung keluar.
- Ada di: master, Jadestone, Medco. Tidak di JOTRE atau Prima Energy.
4. inact_routing_overdue_digest.php: digest overdue, dijaga flag
Membaca enable_routing_overdue_notif_digest langsung dari inweb_config dan, saat menyala, mengirim digest item overdue. Hanya ada di master dan Jadestone; key-nya hanya ada di seed mereka.
5. cron_overdue_mail.php: notifikasi overdue dan akan jatuh tempo, harian
Mengirim pemberitahuan "overdue" dan "due soon" per penerima untuk routing yang mendekati atau melewati rout_due_date, menghormati hari kerja dan libur. Jendela pandang ke depan adalah key .env NOTIF_OVERDUE_SINCE_DAY (1 = peringatan satu hari sebelumnya, default saat kosong; 0 = hari ini; negatif = sudah lewat). Ada di kelima fork.
Menyiapkan cron Multiple Sign Off
Lakukan ini di setiap server yang menjalankan master setelah INA01-866: dev, staging dan produksi. Deploy tidak melakukannya untuk Anda.
1. Periksa prasyarat
| Periksa | Kenapa | Cara memeriksa |
|---|---|---|
Migrasi 20260915090000_alter_ts_multiple_signoff_list_add_map_id sudah jalan | Job membaca ts_multiple_signoff_list.map_id | Deploy dev dan staging menjalankan phinx migrate sendiri. Produksi perlu dijalankan manual: php vendor/bin/phinx migrate |
| PHP CLI, bukan PHP-FPM | Skrip langsung keluar, tanpa output, di SAPI lain (PHP_SAPI !== 'cli') | php -v |
| PHP CLI memuat extension yang sama dengan PHP web | setting.php memuat class Composer, membuat client MongoDB dan butuh curl | php -m lalu bandingkan dengan phpinfo() web |
.env aplikasi ada di root aplikasi | setting.php memuat .env dari root aplikasi. Skrip pindah ke direktori itu sendiri, jadi crontab tidak perlu cd | ls /path/to/app/.env |
baseurl di inweb_config bisa dijangkau dari server itu sendiri | finishApprovalSignOff() memanggil <baseurl>/includes/javascripts/tracking/pdfviewer/web/api/getPDFAfterApprove.php, timeout 600 detik, SSL verify mati | Lihat perintah curl di bawah |
| MongoDB bisa dijangkau | Setiap penulisan yang di-log ($pdo->log()) meng-insert ke collection inweb_logs. Insert yang gagal ditangkap dan dikirim ke log error PHP, jadi tidak menghentikan job | Key MONGO_* di .env |
| User cron bisa menulis folder upload | PDF Transmittal ditulis di bawah docUpload/transmittal | Jalankan job sekali sebagai user itu (langkah 3) |
Pastikan base URL menjawab dari server. Pertama baca nilainya dari database:
SELECT config_value FROM inweb_config WHERE config_name = 'baseurl';Lalu panggil halamannya dari server, dengan nilai itu menggantikan <baseurl>:
curl -k -s -o /dev/null -w '%{http_code}\n' "<baseurl>/includes/javascripts/tracking/pdfviewer/web/api/getPDFAfterApprove.php"Kode HTTP apa pun di bawah 400 berarti baik. Job menganggap error curl atau kode HTTP 400 ke atas sebagai kegagalan.
2. Pasang barisnya dan hapus yang lama
Di Linux dan macOS, tambahkan baris dengan crontab -e sebagai user pemilik file aplikasi:
* * * * * php /path/to/app/cron/cron_multiple_signoff_v2.php >> /var/log/inact_multisignoff.log 2>&1Tanpa lock file dan tanpa flock. Setiap baris antrean diklaim dengan satu UPDATE bersyarat, jadi dua eksekusi yang tumpang tindih tidak pernah mengambil baris yang sama. Karena itu juga barisnya sama saja di Windows.
Di Windows (Tomori jalan di IIS) tidak ada crontab. Buat task Task Scheduler yang berulang tiap menit dan menjalankan perintah yang sama. Path Tomori, dari halaman instance-nya: PHP ada di C:\php\php.exe dan aplikasinya di C:\inetpub\wwwroot\inact, jadi program-nya C:\php\php.exe dan argumennya C:\inetpub\wwwroot\inact\cron\cron_multiple_signoff_v2.php.
TODO: setelan Task Scheduler persisnya untuk job ini di server Windows — nama task, akun yang menjalankannya, dan ke mana output-nya ditulis — belum terdokumentasi di mana pun.
Hapus baris cron_multiple_signoff.php kalau ada (job v1). File-nya sudah tidak ada di master, jadi baris itu hanya mengisi mail cron atau log dengan error. Pastikan file log bisa ditulis oleh user itu.
3. Jalankan sekali secara manual
php /path/to/app/cron/cron_multiple_signoff_v2.php4. Pastikan job berjalan
Pantau log-nya:
tail -f /var/log/inact_multisignoff.logYang dicetak job, diambil dari skripnya:
| Baris | Arti |
|---|---|
multiple sign off queue is empty | Sehat, tidak ada yang dikerjakan. Dicetak sekali per menit saat menganggur |
multiple sign off queue: 3 row(s) | Satu batch dibaca |
queue row 12: taken by another run, skipped | Baris itu sudah diklaim eksekusi lain. Tidak masalah |
routing 120 (map 845): publish lalu published as doc no 9031 | Baris D - Transmit. nothing to publish berarti enable_autopublish mati atau routing tidak punya file dokumen |
routing 121 (map 850): approved document | Baris A / C / S / I, curl ke getPDFAfterApprove.php |
done | Baris selesai (multi_status = 'y') |
WARNING: return transmittal failed: ... | Transmittal return gagal, tetapi baris tetap ditandai selesai, sama seperti Sign Off tunggal |
ERROR: ... | Baris kembali ke 'n' dan jalan lagi menit berikutnya |
done | Akhir batch |
ERROR: cannot read ts_multiple_signoff_list: ..., atau PDOException yang tidak ditangkap | Query antrean gagal. Biasanya migrasi belum jalan, jadi map_id belum ada |
Periksa antrean di database (SQL portabel):
SELECT multi_id, rout_id, map_id, multi_status, cron_ongoing FROM ts_multiple_signoff_list WHERE multi_status = 'n' ORDER BY multi_id;Sehat: baris yang map_id-nya terisi keluar dari daftar ini dalam satu atau dua menit setelah Multiple Sign Off.
5. Bersihkan klaim yang macet
Eksekusi yang terbunuh di tengah jalan (fatal error PHP, kehabisan memori, server restart) meninggalkan barisnya di cron_ongoing = 'y', dan eksekusi berikutnya melewatinya. Pastikan dulu tidak ada eksekusi yang aktif (pgrep -f cron_multiple_signoff_v2.php tidak mencetak apa-apa), lalu:
UPDATE ts_multiple_signoff_list SET cron_ongoing = 'n' WHERE multi_status = 'n' AND cron_ongoing = 'y';Troubleshooting
| Gejala | Penyebab | Perbaikan |
|---|---|---|
Log menampilkan ERROR: getPDFAfterApprove failed: ... setiap menit, baris tetap di n | baseurl tidak terjangkau dari server (DNS, firewall, URL publik yang tidak bisa diakses balik), atau halaman mengembalikan HTTP 400 ke atas | Jalankan cek curl di langkah 1. Perbaiki DNS / hosts atau inweb_config.baseurl |
| Log kosong sama sekali | Baris belum dipasang, path log tidak bisa ditulis, atau PHP bukan binary CLI | crontab -l, cek pemilik file log, php -v |
Baris tetap di n dengan cron_ongoing = 'y' | Eksekusi terbunuh di tengah jalan | Langkah 5 |
Baris tetap di n dengan map_id NULL | Baris lama yang ditulis sebelum INA01-866. Job sengaja melewatinya | Periksa tiap routing secara manual, lalu set multi_status = 'y' |
ERROR: cannot read ts_multiple_signoff_list atau PDOException tentang map_id | Migrasi belum jalan | Jalankan phinx migrate. Sampai itu, setiap Multiple Sign Off di browser juga gagal dengan "Sign off failed" |
ERROR: performer row N not found | Baris performer dihapus setelah sign off | Periksa routing-nya, lalu set baris ke multi_status = 'y' |
Antrean terkuras tetapi routing A tidak dapat dokumen _R | enable_autopublish mati. Job lalu hanya membuat Transmittal return (saat external dan enable_transmittal = 1) | Memang begitu. Nyalakan flag hanya kalau instance memang harus publish |
| Satu eksekusi lebih lama dari satu menit dan eksekusi berikutnya mulai | Wajar. Setiap baris diklaim sendiri, jadi eksekusi kedua hanya mengambil baris yang belum diambil | Tidak perlu apa-apa |
TODO: setelah timeout curl (600 detik) baris dicoba ulang, tetapi request web mungkin tetap selesai di server. Apakah percobaan ulang bisa membangun dokumen
_Rdua kali belum diperiksa.
TODO: publish D - Transmit yang gagal me-rollback database, tetapi PDF Transmittal yang sudah ditulis ke
docUpload/transmittaltetap ada di disk. Apakah file itu dibersihkan di tempat lain belum diperiksa.
Sisa isi cron/
Master menyimpan 18 file. Di luar lima di atas:
| Skrip | Tujuan | Dijaga oleh | Ada di |
|---|---|---|---|
inact_doclib_retention.php | Menandai dan memberi tahu dokumen yang mendekati retensi atau kedaluwarsa | enable_doclib_retention | master, Jadestone, Medco, JOTRE |
inact_direct_update_data.php | Pemeliharaan super-admin, memperbaiki penanda inbox routing yang basi | hanya super-admin | kelima fork |
cron_bypass_overdue.php | Penanganan bypass overdue | — | kelima fork |
cron_create_routing_slip.php | Membuat routing slip untuk cron multiple sign-off lama | — | Jadestone, Medco, JOTRE, Prima Energy. Dihapus dari master oleh INA01-866 |
cron_issue_staging_oversize.php | Email tentang ukuran file dokumen staging. Bukan konverter halaman berukuran besar. | — | kelima fork |
cron_submit_queue.php, procurement_submit_attachment.php, pl_submit_attachment.php | Antrean submission dan lampiran procurement dan packing-list | — | kelima fork |
expediting_weekly_cron.php | Job expediting mingguan (procurement) | — | kelima fork |
cron_dump_db.php | Dump database terjadwal | — | kelima fork |
cron_delete_empty_emailto.php | Pembersihan email | — | kelima fork |
cron_pool_idapd.php | Mengirim email; tujuannya tidak didokumentasikan di file | — | kelima fork |
setting.php | Bootstrap bersama untuk skrip-skrip, bukan job | — | kelima fork |
TODO: untuk apa
cron_pool_idapd.php.
Catatan operasional dan hal yang perlu diwaspadai
- Email sepenuhnya asinkron. Semuanya lewat
ts_emaildan job 1. Job digest dan overdue juga mengantre kets_email, jadi job 1 tetap kritis. - Ketergantungan cURL. Job 1 dan separuh A / C / S / I dari job 2 memanggil balik aplikasi lewat HTTP.
$inweb_baseurlyang salah atau tidak terjangkau membuat job 1 diam-diam tidak berbuat apa-apa, dan membuat job 2 mencoba baris yang sama setiap menit. - Cron yang dijaga flag diam saja saat mati.
inact_routing_digest.php,inact_routing_overdue_digest.phpdaninact_doclib_retention.phpkeluar lebih awal kecuali feature flag-nya diset. Mudah dikira "rusak". - Job Multiple Sign Off yang menganggur tetap menulis satu baris log per menit. Lakukan rotasi
/var/log/inact_multisignoff.log.
Perbedaan antar instance
Diperiksa pada 2026-09-16 di origin/main masing-masing fork. Master dihitung setelah INA01-866.
| Instance | Cron Multiple Sign Off | Perbedaan lain |
|---|---|---|
| Master (setelah INA01-866) | hanya cron_multiple_signoff_v2.php | 18 file |
| Jadestone | cron_multiple_signoff.php dan cron_multiple_signoff_v2.php, plus cron_create_routing_slip.php. v2-nya versi sendiri, bukan file master | 20 file |
| Medco | cron_multiple_signoff_v2.php (versi sendiri), cron_create_routing_slip.php dan cron_create_routing_slip_old.php | 21 file. cron_daily_summary.php masih ada, plus inact_archive_mail.php. Tidak ada inact_routing_overdue_digest.php. |
| JOTRE | cron_multiple_signoff.php (v1) dan cron_create_routing_slip.php | 32 file. Menambah dua belas skrip accurate_* (sinkronisasi dan backfill ke sistem akuntansi Accurate) dan backfill_expediting_chain.php, backfill_mrr_no.php. Tidak ada cron digest. |
| Prima Energy | cron_multiple_signoff.php (v1) dan cron_create_routing_slip.php | 16 file. Tidak ada inact_doclib_retention.php, tidak ada cron digest. |
TODO: file mana yang dijadwalkan server Jadestone, v1 atau v2, saat keduanya ada.
Terkait
- Multiple Sign Off mengisi antrean
ts_multiple_signoff_listyang dikuras job 2. - Sign Off: sign off tunggal yang ditiru job ini.
- inweb_config mencantumkan flag yang menjaga cron digest dan retention.