- Laravel นำเสนอ API คิวแบบรวมที่มีไดรเวอร์หลายตัว (ฐานข้อมูล, Redis, SQS…) และการแยกระหว่างการเชื่อมต่อและคิวเชิงตรรกะ
- งานเหล่านี้ช่วยให้สามารถย้ายงานหนักๆ ไปที่พื้นหลังได้ โดยรองรับการทำโมเดลแบบอนุกรม มิดเดิลแวร์ งานครั้งเดียว การเข้ารหัส ชุดงาน และสตริง
- คนงานได้รับการจัดการด้วยคิว:งาน หัวหน้างาน และคำสั่งเช่นคิว:หยุดชั่วคราว/คิว:ดำเนินการต่อ ซึ่งควบคุมการลองใหม่ การหมดเวลา และลำดับความสำคัญ
- มีระบบนิเวศที่สมบูรณ์สำหรับความล้มเหลว การตรวจสอบ และการทดสอบ (failed_jobs, queue:retry, queue:monitor, Queue::fake) ที่ทำให้คิวเชื่อถือได้ในการผลิต
การทำงานกับคิวใน Laravelแทบจะเป็นสิ่งที่จำเป็นในโปรเจ็กต์ที่จริงจังทุกโปรเจ็กต์ ไม่ว่าจะเป็นการส่งอีเมล การประมวลผลไฟล์ CSV การสร้างไฟล์ PDF การปรับขนาดรูปภาพ การเรียกใช้ API ภายนอก... หากทำทั้งหมดนี้ในคำขอ HTTP หลัก เว็บไซต์จะทำงานช้าลง เกิดข้อผิดพลาด 500 และผู้ใช้ก็จะพบแต่หน้าจอว่างเปล่าอย่างสิ้นหวัง
ข่าวดีก็คือ Laravel มีโครงสร้างพื้นฐานการจัดคิวที่มีประสิทธิภาพและยืดหยุ่นซึ่งช่วยให้คุณสามารถมอบหมายงานหนักให้กับกระบวนการทำงานเบื้องหลัง จัดการลำดับความสำคัญ จัดกลุ่มเป็นชุด ตรวจสอบสถานะการทำงาน ลองใหม่เมื่อล้มเหลว และแม้กระทั่งหยุดการทำงานของกระบวนการเหล่านั้นชั่วคราวเพื่อการบำรุงรักษา มาดูกันอย่างละเอียด (และไม่พลาดสิ่งใด) ว่าจะใช้ประโยชน์จากมันให้ได้มากที่สุดได้อย่างไร รวมถึงวิธีการหยุดชั่วคราว เริ่มใหม่ และควบคุมพฤติกรรมของมันในสภาพแวดล้อมการใช้งานจริง
แนวคิดพื้นฐาน: การเชื่อมต่อ คิว และไดรเวอร์
ใน Laravel ก่อนที่จะหยุดอะไรก็ตาม คุณต้องเข้าใจความแตกต่างระหว่าง การเชื่อมต่อคิวและคิวเอง. ใน config/queue.php คุณมีอาร์เรย์ connections ซึ่งคุณกำหนดแบ็กเอนด์แต่ละรายการ: ฐานข้อมูล, redis, beanstalkd, sqs, ซิงค์, null, failover, rabbitmq (หากคุณเพิ่มมันเข้าไป) ฯลฯ
การเชื่อมต่อแต่ละครั้งสามารถมีได้หลาย คิวเชิงตรรกะ (ชื่อเช่น default, emails, high, low, importsคุณสมบัติ queue การเชื่อมต่อแต่ละครั้งจะระบุว่าคิวเริ่มต้นใดที่งานจะไปหากไม่ได้ระบุอื่นไว้ onQueue()ด้วยวิธีนี้คุณสามารถทำสิ่งต่างๆ เช่น:
- คิวด่วน สำหรับอีเมล์หรือธุรกรรมสั้นๆ
- ความสำคัญต่ำอีกประการหนึ่ง สำหรับงานที่ยาวนานเช่นการประมวลผลวิดีโอหรือรายงานขนาดใหญ่
- คิวแบ่งตามประเภทงาน:
imports,notificaciones,reportesฯลฯ
เมื่อคุณเปิดตัวเวิร์กเกอร์ด้วย php artisan queue:workโดยค่าเริ่มต้นจะฟังคิวที่ระบุเป็น ค่าเริ่มต้น บนการเชื่อมต่อที่เลือก หากต้องการจัดลำดับความสำคัญ คุณสามารถส่งคิวที่คั่นด้วยเครื่องหมายจุลภาคหลายรายการได้:
php artisan queue:work redis --queue=high,default,low
ด้วยวิธีนี้ พนักงานจะประมวลผลงานที่มีความสำคัญสูง ก่อน จากนั้นจึงประมวลผลงานระดับเริ่มต้นและสุดท้ายจึงประมวล ผลงาน ระดับต่ำซึ่งเป็นสิ่งสำคัญอย่างยิ่งเมื่อระบบมีภาระงานมาก และคุณไม่ต้องการให้รายงานที่ใช้เวลา 30 นาทีไปบดบังอีเมลที่มีความสำคัญสูง
ไดรเวอร์คิวและข้อกำหนดเบื้องต้น
Laravel มี API ที่เป็นมาตรฐานสำหรับตัวจัดการคิว หลายตัว แต่ละตัวก็มีคุณสมบัติและส่วนประกอบเฉพาะของตัวเอง การเลือกตัวจัดการคิวที่เหมาะสมเป็นสิ่งสำคัญอย่างยิ่งก่อนที่จะพูดถึงการหยุดการทำงานของเวิร์กเกอร์
ฐานข้อมูลไดรเวอร์
คนขับ ฐานข้อมูล มันเก็บงานไว้ในตาราง SQL (โดยปกติ jobsตั้งค่าได้ง่ายและเหมาะอย่างยิ่งสำหรับโปรเจ็กต์ขนาดเล็กหรือสภาพแวดล้อมการพัฒนาที่คุณไม่ต้องการยุ่งยากกับ Redis หรือ SQS
ขั้นตอนพื้นฐาน:
- สร้างการโยกย้าย:
php artisan queue:table(หรือในเวอร์ชันใหม่กว่านั้นก็มาเป็นcreate_jobs_tableค่าเริ่มต้น). - ดำเนินการย้ายข้อมูล:
php artisan migrate. - การกำหนดค่า QUEUE_CONNECTION=ฐานข้อมูล ใน
.envและยืนยันในconfig/queue.phpนี้'default' => env('QUEUE_CONNECTION','database').
มันสะดวกและมีความเสถียรเพียงพอ แต่หากมีคิวจำนวนมากและปริมาณการใช้งานสูง มันอาจกลายเป็นคอขวดได้ เนื่องจากทุกอย่างต้องผ่านฐานข้อมูลเชิงสัมพันธ์เดียวกัน
ไดร์เวอร์ เรดิส
ไดรเวอร์Redisเป็นเครื่องมือมาตรฐานที่ใช้กันอย่างแพร่หลายในระบบการผลิต มันทำงานเร็ว รองรับคุณสมบัติขั้นสูง (การล็อก การจำกัดอัตรา การล็อกแบบอะตอมิก Horizon ฯลฯ) และปรับขนาดได้ดีมาก
จุดสำคัญ:
- คุณต้องกำหนดค่าการเชื่อมต่อ Redis ใน
config/database.php. - ตัวเลือก
serializerycompressionจาก Redis พวกเขาเข้ากันไม่ได้ พร้อมพนักงานขับรถคิว - ถ้าคุณใช้ คลัสเตอร์ Redisชื่อคิวต้องมีแฮชแท็ก เช่น
{default}เพื่อให้คีย์ทั้งหมดในคิวนั้นตกอยู่ในช่องเดียวกัน - ตัวเลือก
block_forมันช่วยให้คนงานสามารถบล็อคได้ในขณะที่รองานเป็นเวลาสองสามวินาที แทนที่จะทำการโพลอย่างต่อเนื่อง: ประหยัดซีพียู และลดการสอบถามไปยังเซิร์ฟเวอร์ Redis
ตัวอย่างเช่น:
'redis' => ,
หากคุณใส่ block_for = 0คนงานจะถูกบล็อกอย่างไม่มีกำหนดจนกว่าจะมีงานว่าง ซึ่งเป็นสิ่งที่ต้องคำนึงถึงหากคุณต้องการให้คนงานตอบสนองต่อสัญญาณต่างๆ อย่างรวดเร็ว เช่น SIGTERM หรือคำสั่งหยุดชั่วคราว
ไดรเวอร์อื่นๆ: SQS, Beanstalkd, null, failover…
นอกเหนือจากฐานข้อมูลและ Redis แล้ว Laravel ยังรองรับระบบอื่นๆ อีกด้วย:
- อเมซอน SQSจัดการคิวบน AWS พร้อมรองรับ FIFOกลุ่มข้อความ การลบข้อมูลซ้ำซ้อน และการตั้งค่าการมองเห็นขั้นสูง ต้องใช้ SDK
aws/aws-sdk-php. - ถั่วฝักยาวรวดเร็วและง่ายมากโดยใช้แพ็คเกจ
pda/pheanstalk. - ซิงค์: ดำเนินการตามภารกิจ ทันที ในกระบวนการเดียวกัน มีประโยชน์ในการพัฒนาหรือทดสอบ แต่ในการผลิตก็แทบจะเหมือนกับไม่ต้องใช้คิวเลย
- โมฆะ: ยกเลิกงานทันทีที่ "ส่งออก" ใช้เพื่อปิดใช้งานระบบคิวโดยสมบูรณ์
- ล้มเหลววิธีนี้ช่วยให้คุณกำหนดค่าการเชื่อมต่อได้หลายรายการ และหากการเชื่อมต่อหลักล้มเหลว Laravel จะพยายามส่งงานไปยังการเชื่อมต่อถัดไปในรายการ เหมาะสำหรับสภาพแวดล้อมที่ ความพร้อมใช้งานสูง เป็นสิ่งสำคัญ
ในส่วนของการหยุดและเริ่มการทำงานของเวิร์กเกอร์นั้น ตรรกะแทบจะเหมือนกันไม่ว่าจะเป็นไดรเวอร์ใดก็ตาม เพราะมันถูกจัดการจากคำสั่ง Artisan และ คลาส Workerไม่ใช่จากแบ็กเอนด์ของคิว
การสร้างงานและการสร้างโมเดลแบบอนุกรม
Un การสัมภาษณ์ ใน Laravel มันเป็นเพียงคลาสที่ห่อหุ้มงานที่ต้องดำเนินการในคิว โดยทั่วไปจะสร้างขึ้นด้วย Artisan และบันทึกไว้ใน app/Jobs.
เพื่อสร้างอันหนึ่ง:
php artisan make:job ProcessPodcast
คลาสที่สร้างขึ้น ดำเนินการ ShouldQueue และโดยปกติจะใช้ลักษณะ Dispatchable, InteractsWithQueue, Queueable y SerializesModelsหัวใจอยู่ที่วิธีการ handle()ซึ่งเป็นสิ่งที่คนงานทำเมื่องานมาถึง
คุณสมบัติที่ทรงพลังอย่างยิ่งอย่างหนึ่งคือการแปลงโมเดล Eloquent เป็นรูปแบบที่สามารถจัดเก็บและอ้างอิงได้โดยอัตโนมัติหากคุณยอมรับโมเดลในตัวสร้าง Job นั้น Laravel จะไม่เพิ่มอ็อบเจ็กต์ทั้งหมดลงในคิว แต่จะเพิ่มเฉพาะตัวระบุเท่านั้น เมื่อ Job ถูกประมวลผล ระบบจะสร้างโมเดลขึ้นใหม่จากฐานข้อมูลพร้อมกับโหลดความสัมพันธ์ต่างๆ
ตัวอย่างทั่วไป (ในรูปแบบซูโดโค้ด เพื่อหลีกเลี่ยงการทำซ้ำคำต่อคำ):
- ผู้สร้างได้รับ พอดแคสต์ พอดแคสต์.
- ลักษณะนิสัย
SerializesModelsมีหน้าที่รับผิดชอบในการบันทึก ID - En
handle(AudioProcessor $processor)คุณทำหน้าที่หนักๆ (เช่น การประมวลผลเสียง)
หากคุณไม่ต้องการให้ความสัมพันธ์ในโมเดลเป็นแบบอนุกรม (เพื่อให้เพย์โหลดไม่ใหญ่มาก) คุณสามารถใช้ $model->withoutRelations() หรือใน PHP 8 แอตทริบิวต์ # บนทรัพย์สินที่ได้รับการส่งเสริมของผู้สร้าง
การฉีดการอ้างอิงในวิธีการจัดการ
ข้อดีอีกอย่างก็คือคุณสามารถ ฉีดบริการลงในวิธีการจัดการโดยตรง (ราวกับว่าเป็นตัวควบคุม) เนื่องจาก Laravel ยังใช้คอนเทนเนอร์บริการในงานด้วย ตัวอย่างเช่น คุณสามารถร้องขอ AudioProcessorไคลเอนต์ HTTP, ที่เก็บข้อมูล ฯลฯ และกรอบงานจะดูแลการแก้ไขปัญหาเหล่านี้
หากคุณต้องการการควบคุมที่ละเอียดเป็นพิเศษของสิ่งที่เรียกว่า handleคุณสามารถใช้ Container::bindMethod() ในผู้ให้บริการและกำหนดตรรกะการฉีดด้วยตัวเอง แต่ในกรณีส่วนใหญ่ไม่จำเป็นต้องทำให้สิ่งต่างๆ ซับซ้อนมากนัก
งานมิดเดิลแวร์
เช่นเดียวกับเส้นทางที่มีมิดเดิลแวร์ จ็อบส์ก็สามารถมีได้เช่นกัน มิดเดิลแวร์เฉพาะ ที่รันก่อนและหลังงาน ซึ่งจะช่วยลดความซ้ำซ้อนของโค้ดในเมธอดได้อย่างมาก handle() และมีประโยชน์อย่างยิ่งสำหรับ:
- การจำกัดอัตรา กับ Redis
- หลีกเลี่ยง คาบเกี่ยวกัน ของงานที่สัมผัสกับทรัพยากรเดียวกัน
- ข้อยกเว้นปกติ สำหรับ API ที่ไม่เสถียร
- การข้ามงานภายใต้เงื่อนไขบางประการ (
Skipมิดเดิลแวร์)
มิดเดิลแวร์มักจะถูกวางไว้ใน app/Jobs/Middleware และถูกส่งกลับจากวิธีการ middleware() จากงาน ตัวอย่างแนวคิด:
public function middleware(): array { return ;
ประเภทงานพิเศษ: ไม่ซ้ำกัน เข้ารหัส และล็อค
Laravel ช่วยให้คุณสามารถทำเครื่องหมายงานบางอย่างได้ ไม่เหมือนใคร เพื่อให้แน่ใจว่าไม่มีอินสแตนซ์ที่เหมือนกันสองอินสแตนซ์ถูกจัดคิวพร้อมกัน วิธีนี้ทำได้โดยการใช้อินเทอร์เฟซ ShouldBeUnique o ShouldBeUniqueUntilProcessingและรองรับการกำหนดคีย์ uniqueId() และเวลา uniqueFor.
เหมาะอย่างยิ่งสำหรับสิ่งต่างๆ เช่น:
- คำนวณดัชนีการค้นหาผลิตภัณฑ์ใหม่: เพียงครั้งเดียวต่อผลิตภัณฑ์ จนกว่าจะเสร็จสิ้น
- การซิงโครไนซ์กับบริการภายนอกที่ไม่อนุญาตให้มีการร้องขอพร้อมกันสำหรับทรัพยากรเดียวกัน
ด้านล่าง Laravel ใช้ ล็อคอะตอม ของแคช (Redis, memcached, ฐานข้อมูล ฯลฯ) คุณยังสามารถเลือกไดรเวอร์แคชสำหรับล็อคนั้นได้ด้วย uniqueVia().
นอกจากนี้ยังมีอินเทอร์เฟซ ShouldBeEncryptedโดยที่คุณระบุว่างานเสร็จสมบูรณ์แล้ว กรอกรหัสของคุณก่อนเข้าคิวมีประโยชน์มากเมื่อส่งข้อมูลที่ละเอียดอ่อนและคุณไม่ต้องการให้ข้อมูลเดินทางในรูปแบบข้อความธรรมดาผ่าน Redis, SQS หรือฐานข้อมูล
การจัดส่ง การล่าช้า และการดำเนินการงานในโหมดที่แตกต่างกัน
เมื่อคุณกำหนดงานของคุณแล้ว ให้เริ่มต้นงานด้วย Job::dispatch() จากตัวควบคุม ตัวรับฟังเหตุการณ์ คำสั่ง Artisan หรือแม้แต่การปิด พารามิเตอร์ที่คุณส่งไป dispatch พวกเขาตรงไปหาผู้สร้างโยบ
รูปแบบที่น่าสนใจ:
dispatchIf()ydispatchUnless()เพื่อปรับสภาพการจัดส่งให้เป็นบรรทัดเดียวdelay()เพื่อป้องกันไม่ให้งานดำเนินการได้จนกว่าจะถึงวันที่/เวลาที่กำหนดdispatchAfterResponse()oafterResponse()endispatch()การปิดซึ่งจะเลื่อนการดำเนินการจนกว่าจะส่งการตอบสนอง HTTP แต่ภายในกระบวนการ PHP เดียวกันdispatchSync()ในการรันงานแบบซิงโครนัส (โดยไม่ผ่านคิว) แต่ใช้คลาสเดียวกันซ้ำ- การเชื่อมต่อพิเศษเช่น
deferredobackgroundเพื่อดำเนินการหลังจากการตอบสนองในกระบวนการเดียวกันหรือในกระบวนการ PHP ใหม่
สุดท้ายคุณสามารถระบุการเชื่อมต่อและคิวด้วยวิธีการแบบเชื่อมโยงได้ onConnection() y onQueue()ไม่ว่าจะเป็นเมื่อจัดส่งหรือภายในตัวสร้างงาน
การควบคุมละเอียด: การลองใหม่ การถอยกลับ การหมดเวลา และการจัดการข้อผิดพลาด
ส่วนสำคัญของการทำงานกับคิวใน Laravel คือการตัดสินใจว่าจะลองดำเนินการงานซ้ำกี่ครั้งจะรอเวลานานเท่าใดระหว่างการลองแต่ละครั้ง และเมื่อใดจึงจะถือว่างานนั้นล้มเหลว
ตัวเลือกที่มีจำหน่าย:
--triesenqueue:workเพื่อกำหนดจำนวนสูงสุดของความพยายามสำหรับงานทั้งหมดของพนักงานนั้น (ยกเว้นว่างานจะกำหนดของตัวเอง)$triesotries()).$triesหรือวิธีการtries()ในคลาสงานสำหรับการควบคุมแต่ละงานretryUntil()ที่จะพูดว่า: “ลองใหม่อีกครั้งเท่าที่คุณอยากลอง จนกระทั่งถึงเวลานั้น หลังจากนั้นก็ล้มเหลว” ถ้ามันตรงกับtries, สั่งการretryUntil.$maxExceptionsเพื่อตัดออกเมื่อปัญหาเกิดจากข้อยกเว้นที่ไม่ได้รับการจัดการซ้ำๆ$timeouto--timeoutเพื่อระบุว่างานสามารถทำงานได้กี่วินาทีก่อนที่เวิร์กเกอร์จะหยุดกระบวนการย่อย$failOnTimeoutเพื่อทำเครื่องหมายงานว่าล้มเหลวในกรณีที่หมดเวลา$backoffวิธีการbackoff()เพื่อกำหนดระยะเวลาในการรอระหว่างการลองใหม่อีกครั้ง แม้ว่าจะมีค่าเลขชี้กำลังก็ตาม
หากงานโยนข้อยกเว้นที่ไม่ถูกจับได้ Laravel จะ... ปล่อยกลับเข้าหางอีกครั้ง จนกว่าจะหมดความพยายามที่ตั้งค่าไว้ คุณสามารถควบคุมสิ่งนี้ด้วยตนเองได้ด้วย release($segundos) o fail($exception) เมื่อคุณต้องการทำเครื่องหมายงานว่าล้มเหลวโดยเจตนา
งานที่ล้มเหลว ตารางงานที่ล้มเหลว และการตัดแต่ง
เมื่องานหมดความพยายามของเขาแล้ว เขาจะได้รับการพิจารณา งานล้มเหลว และ Laravel จะแทรกมันเข้าไปในตาราง failed_jobs (หรือใน DynamoDB หากคุณกำหนดค่าไว้แบบนั้น) ตารางดังกล่าวจะจัดเก็บ UUID การเชื่อมต่อ คิว เพย์โหลดงาน และข้อยกเว้นที่เกิดขึ้น
คำสั่งที่เป็นประโยชน์:
php artisan queue:failedเพื่อแสดงรายการที่ล้มเหลวphp artisan queue:retry <id|all>เพื่อลองมันอีกครั้งphp artisan queue:forget <id>ที่จะลบอันหนึ่งphp artisan queue:flushเพื่อลบทั้งหมด (พร้อมตัวเลือกเป็นชั่วโมงในเวอร์ชันใหม่กว่า)php artisan queue:prune-failed --hours=48เพื่อทำการตัดแต่งบันทึกเก่าโดยอัตโนมัติ
ในงานคุณสามารถกำหนดวิธีการได้ failed(Throwable $exception) สำหรับการล้างข้อมูลเพิ่มเติม: แจ้งให้ผู้ใช้ทราบ ย้อนกลับการดำเนินการบางส่วน เขียนบันทึกเฉพาะ ฯลฯ โปรดทราบว่ามีการสร้างอินสแตนซ์ใหม่ของงานเพื่อเรียก failed()ดังนั้นอย่าพึ่งพึ่งการเปลี่ยนแปลงทรัพย์สินที่เกิดขึ้น handle().
การแบ่งงานเป็นชุด: การแบ่งงานเป็นชุดและรวมเข้าด้วยกันด้วยสตริง
เมื่อคุณต้องการเริ่มงานที่เกี่ยวข้องกันหลายร้อยหรือหลายพันรายการ (ตัวอย่างเช่น การนำเข้าไฟล์ CSV ขนาดใหญ่เป็นส่วนๆ การประมวลผลไฟล์เป็นชุด การทำความสะอาดข้อมูล ฯลฯ) ขอแนะนำให้ใช้ ฟังก์ชันการประมวลผลแบบกลุ่มของ Laravel
การไหลพื้นฐาน:
- สร้างตาราง
job_batchesกับphp artisan queue:batches-table && php artisan migrate. - ทำเครื่องหมายงานที่จะเป็นส่วนหนึ่งของชุดด้วยคุณลักษณะ
Batchable. - ใช้
Bus::batch()เพื่อส่งชุดงานพร้อมการโทรกลับthen,catchyfinally. - เข้าถึงชุดงานจากแต่ละงานด้วย
$this->batch()และตรวจสอบว่ามันถูกยกเลิกหรือไม่ - ความเป็นไปได้ในการเพิ่มงานเพิ่มเติมให้กับชุดงานที่กำลังดำเนินอยู่ด้วย
$this->batch()->add().
การประมวลผลแบบกลุ่ม (Batch) ผสานรวมกับการประมวลผลแบบต่อเนื่อง (Chain) ได้อย่างลงตัว:คุณสามารถสร้างการประมวลผลแบบต่อเนื่องภายในกลุ่ม หรือใช้กลุ่มเป็นส่วนประกอบของการประมวลผลแบบต่อเนื่องที่ใหญ่กว่าได้ ซึ่งมีประโยชน์อย่างยิ่งเมื่อคุณต้องการให้การประมวลผลแบบต่อเนื่องหลายๆ อย่างทำงาน "พร้อมกัน" และเรียกใช้งานบางอย่างเมื่อการประมวลผลทั้งหมดเสร็จสมบูรณ์
การดำเนินการของพนักงาน ลำดับความสำคัญ และการปรับใช้
ความมหัศจรรย์ของคิวเกิดขึ้นเพราะคุณมี คนงานหนึ่งคนหรือมากกว่า เรียกใช้คำสั่ง queue:work (o queue:listen(แม้ว่าอย่างหลังจะมีประสิทธิภาพน้อยกว่าก็ตาม) กระบวนการเหล่านี้เป็นเดมอนที่ทำงานยาวนานซึ่งคอยฟังคิวที่เกี่ยวข้อง
ตัวเลือกหลักของ queue:work:
- Conexion:
php artisan queue:work redis,queue:work databaseฯลฯ - โคลาส:
--queue=high,default,lowการจัดลำดับความสำคัญ - -สิบเอ็ด: ประมวลผลงานเดียวและออก
- –งานสูงสุด: ประมวลผลงาน X และยุติ (เพื่อรีสตาร์ทเวิร์กเกอร์เป็นระยะและเพิ่มหน่วยความจำ)
- –เวลาสูงสุด:ประมวลผลเป็นเวลา N วินาทีแล้วออก
- -นอน: วินาทีแห่งการรอคอยเมื่อไม่มีงานว่าง
- หยุดเมื่อว่าง: ล้างคิวและปิดอย่างเรียบร้อย (เหมาะอย่างยิ่งในสภาพแวดล้อม Docker หรืองานครั้งเดียว)
- –หมดเวลา: วินาทีของการหมดเวลาต่องาน ดังที่เราได้กล่าวไว้ก่อนหน้านี้
- -บังคับ: เพื่อประมวลผลงานแม้ว่าแอปจะอยู่ในโหมดการบำรุงรักษาก็ตาม
เนื่องจากกระบวนการเหล่านี้ใช้เวลานาน ในสภาพแวดล้อมการใช้งานจริง จึงมักใช้ โปรแกรมตรวจสอบกระบวนการเช่น Supervisor (บน Linux) เพื่อเริ่มการทำงานของ X worker เริ่มใหม่หากเกิดข้อผิดพลาด และจัดการบันทึกต่างๆ บล็อกการกำหนดค่า Supervisor ทั่วไปสำหรับ Laravel จะกำหนดดังนี้:
- คำสั่ง ที่มีการ
php artisan queue:work ...คอนกรีต. - ตัวเลข เพื่อระบุจำนวนคนงานที่จะเปิดตัวพร้อมกัน
- เส้นทางบันทึก ผู้ใช้ การรีสตาร์ทอัตโนมัติ ฯลฯ
การหยุดชั่วคราวและการเริ่มคิวใหม่ใน Laravel
มาดูกันว่าอะไรคือสิ่งที่สำคัญในการบำรุงรักษา: วิธีการหยุดการทำงานของคิวชั่วคราวโดยไม่หยุดการทำงานอย่างกะทันหันและไม่ทิ้งงานไว้ให้ไม่เสร็จ Laravel มีกลไกหลายอย่าง ทั้งแบบใหม่และแบบดั้งเดิม เพื่อควบคุมเรื่องนี้
หยุดชั่วคราว: คิว: หยุดชั่วคราวและขัดจังหวะสัญญาณ
ในเวอร์ชันล่าสุด Laravel ได้เพิ่มคำสั่งเฉพาะเพื่อหยุดและเริ่มการทำงานของเวิร์กเกอร์อีกครั้ง:
php artisan queue:pause: บอกให้ระบบหยุดรับงานใหม่ แต่ปล่อยให้งานที่กำลังดำเนินการอยู่ทำต่อจนเสร็จphp artisan queue:continue:กลับมาดำเนินการงานใหม่ต่อจากจุดที่ค้างไว้
คำสั่งเหล่านี้ทำงานโดยการส่งสัญญาณไปยังเวิร์กเกอร์ผ่านกลไกการแคชที่ Laravel ใช้ภายใน นั่นเป็นเหตุผลว่าทำไมการตั้งค่าไดรเวอร์แคช (memcached, redis, ฐานข้อมูล, ไฟล์ ฯลฯ) ให้ถูกต้องจึงมีความสำคัญ แม้ว่าคิวแคชจริงของคุณจะเป็นอย่างอื่นก็ตาม
ข้อสำคัญ: การหยุดคิวหรือตัวประมวลผลชั่วคราวไม่ได้เป็นการยกเลิกหรือลบงานที่อยู่ในคิวอยู่แล้วแต่เป็นการป้องกันไม่ให้มีการลบงานเพิ่มเติมออกจากคิวในระหว่างที่การหยุดชั่วคราวนั้นมีผลอยู่
การสำรวจการหยุดชะงักและผลกระทบต่อประสิทธิภาพการทำงาน
ทุกครั้งที่ worker ทำงานเสร็จสิ้น Laravel จะตรวจสอบแคชเพื่อหา สัญญาณ รีสตาร์ท หยุดชั่วคราว หรือดำเนินการต่อ การตรวจ สอบ นี้มีค่าใช้จ่ายน้อยมาก แต่ก็มีอยู่ หากคุณให้ความสำคัญกับประสิทธิภาพเป็นอย่างมากและรู้ว่าคุณไม่จำเป็นต้องหยุดชั่วคราวหรือรีสตาร์ท worker จากคำสั่ง คุณสามารถปิดการตรวจสอบนี้ได้โดยการเรียกใช้:
Queue::withoutInterruptionPolling();
หรือแม้กระทั่งปรับคุณสมบัติคงที่ของ Illuminate\Queue\Worker เพื่อปิดการใช้งานการสัมผัสเฉพาะ (รีสตาร์ทได้, หยุดชั่วคราวได้อย่างไรก็ตามหากคุณทำสิ่งนี้แล้วลองใช้ queue:pause o queue:restartคนงาน พวกเขาจะไม่พบเป็นการตัดสินใจด้านการออกแบบที่ควรพิจารณาอย่างรอบคอบ
หยุดชั่วคราวด้วยตนเองด้วย Supervisor หรือ Docker
นอกเหนือจากคำสั่งของ Laravel เองแล้วในสภาพแวดล้อมการใช้งานจริง กระบวนการต่างๆ มักจะถูก "หยุดชั่วคราว" โดยอ้อม:
- การหยุดโปรแกรมใน Supervisor (
supervisorctl stop laravel-worker:*) ซึ่งจะฆ่าหรือหยุดคนงาน - การใช้ หยุดเมื่อว่าง ในการปรับใช้เพื่อให้คนงานทำสิ่งที่อยู่ในคิวให้เสร็จก่อนแล้วจึงปิดระบบ
- ใน Docker ให้คอนเทนเนอร์ประมวลผลด้วย
--stop-when-emptyแล้วมันก็ดับไป
ความแตกต่างกับ queue:pause เมื่อหยุดกระบวนการทั้งหมดแล้ว คุณจะหยุดการประมวลผลงานจนกว่าคนงานจะเริ่มต้นใหม่ การหยุดชั่วคราวภายใน คุณสามารถเก็บกระบวนการไว้ในหน่วยความจำโดยรอคำสั่ง continueซึ่งมีประโยชน์สำหรับการปรับใช้ย้อนกลับอย่างรวดเร็วหรือช่วงการบำรุงรักษาที่สั้น
ธุรกรรมฐานข้อมูลและ after_commit
ข้อผิดพลาดคลาสสิก: การส่งงาน ภายใน ธุรกรรมฐานข้อมูล หากคุณไม่ระมัดระวัง ตัวประมวลผลอาจดำเนินการงานนั้นก่อนที่จะมีการยืนยันการเปลี่ยนแปลง และโมเดลหรือข้อมูลที่คุณคาดหวังอาจยังไม่ปรากฏในฐานข้อมูล
เพื่อหลีกเลี่ยงการเต้นรำนี้ คุณมีสองทางเลือก:
- กระตุ้น
'after_commit' => trueในการกำหนดค่าการเชื่อมต่อคิว ดังนั้น งานใดๆ ที่จัดส่งภายในธุรกรรมจะถูกเลื่อนออกไปภายในจนกว่าจะได้รับการยืนยัน - ใช้วิธีการแบบต่องาน
afterCommit()obeforeCommit()เมื่อทำการจัดส่ง ให้บังคับให้มีการทำงานเฉพาะในงานที่กำหนดเท่านั้น
หากธุรกรรมถูกยกเลิก งานที่ถูกส่งไปในระหว่างธุรกรรมนั้นจะถูกทิ้งโดยไม่เข้าสู่คิว ซึ่งเป็นสิ่งที่โดยทั่วไปแล้วต้องการเพื่อรักษาความสม่ำเสมอ
การติดตาม การทำความสะอาดคิว และการทดสอบ
เมื่อคุณตั้งค่าและใช้งานระบบคิวได้อย่างจริงจังแล้ว การแค่ส่งงานออกไปแล้วปล่อยทิ้งไว้โดยไม่สนใจนั้นไม่เพียงพอ คุณควรตรวจสอบและทดสอบการทำงานของทุกอย่างอย่างสม่ำเสมอ
เครื่องมือและคำสั่งที่เป็นประโยชน์:
queue:clearเพื่อล้างคิวที่ระบุ (SQS, Redis, ฐานข้อมูล)queue:monitorเพื่อตรวจสอบจำนวนงานในคิวบางรายการและทริกเกอร์เหตุการณ์QueueBusyหากเกินเกณฑ์ที่กำหนด- กิจกรรมงาน ในขณะที่
Queue::before,Queue::after,Queue::loopingyQueue::failingเพื่อเชื่อมโยงตรรกะที่กำหนดเอง (บันทึก เมตริก การย้อนกลับ ฯลฯ) - ของปลอมในการทดสอบ การใช้
Queue::fake()yBus::fake()เพื่อตรวจยืนยันว่างาน สตริง หรือชุดงานได้รับการส่งไปแล้วโดยไม่ได้ดำเนินการจริง
ในการทดสอบ คุณสามารถระบุสิ่งต่างๆ เช่น"งานนี้ถูกจัดคิวไว้ X ครั้ง" "ชุดงานเหล่านี้ถูกส่งไปตามลำดับนี้" หรือ "ไม่มีงานใดถูกจัดคิวไว้โดยเฉพาะ" ซึ่งช่วยเพิ่มความปลอดภัยในกระบวนการทำงานที่ซับซ้อนได้มาก
ด้วยระบบนิเวศน์ทั้งหมดนี้—ไดรเวอร์เช่น Redis หรือ SQS งานที่ได้รับการออกแบบอย่างดี มิดเดิลแวร์สำหรับการปรับแต่ง ชุดข้อมูล โซ่ การกำหนดค่าการลองใหม่ พนักงานที่จัดการโดยหัวหน้างาน และคำสั่งเช่น queue:pause y queue:continueLaravel ช่วยให้คุณสามารถควบคุมการประมวลผลพื้นหลังได้ในระดับมิลลิเมตร ตั้งแต่การส่งอีเมลทั่วไปไปจนถึงสถาปัตยกรรมคิวแบบกระจายพร้อมระบบเฟลโอเวอร์ ช่วยให้มั่นใจได้ว่าแอปพลิเคชันของคุณยังคงตอบสนองได้อย่างรวดเร็วที่เลเยอร์ HTTP ในขณะที่งานหนักกำลังดำเนินการอยู่ด้านล่าง โดยไม่บล็อกผู้ใช้