ตามหลักการของคำตอบจากuser1599237ซึ่งคุณปล่อยให้งาน cron ทำงานบนอินสแตนซ์ทั้งหมด แต่ในช่วงเริ่มต้นของงานจะพิจารณาว่าควรได้รับอนุญาตให้ทำงานหรือไม่ฉันได้ทำวิธีแก้ปัญหาอื่นแล้ว
แทนที่จะดูอินสแตนซ์ที่กำลังทำงานอยู่ (และต้องจัดเก็บคีย์และความลับ AWS ของคุณ) ฉันใช้ฐานข้อมูล MySQL ที่ฉันเชื่อมต่ออยู่แล้วจากอินสแตนซ์ทั้งหมด
ไม่มีข้อเสียมี แต่ผลบวก:
- ไม่มีอินสแตนซ์หรือค่าใช้จ่ายเพิ่มเติม
- สารละลายแข็งของหิน - ไม่มีโอกาสในการดำเนินการสองครั้ง
- ปรับขนาดได้ - ทำงานโดยอัตโนมัติเมื่ออินสแตนซ์ของคุณถูกปรับขนาดขึ้นและลง
- เฟลโอเวอร์ - ทำงานโดยอัตโนมัติในกรณีที่อินสแตนซ์เกิดความล้มเหลว
หรือคุณยังสามารถใช้ระบบไฟล์ที่ใช้ร่วมกันทั่วไป (เช่นAWS EFSผ่านโปรโตคอล NFS) แทนฐานข้อมูล
โซลูชันต่อไปนี้สร้างขึ้นภายในเฟรมเวิร์ก PHP Yiiแต่คุณสามารถปรับให้เข้ากับเฟรมเวิร์กและภาษาอื่นได้อย่างง่ายดาย นอกจากนี้ตัวจัดการข้อยกเว้นYii::$app->system
ยังเป็นโมดูลของฉันเอง แทนที่ด้วยสิ่งที่คุณกำลังใช้
public function actionLock() {
$argsAll = $args = func_get_args();
if (!is_numeric($args[0])) {
\Yii::$app->system->error('Duration for obtaining process lock is not numeric.', ['Args' => $argsAll]);
}
if (!$args[1]) {
\Yii::$app->system->error('Job name for obtaining process lock is missing.', ['Args' => $argsAll]);
}
$durationMins = $args[0];
$jobName = $args[1];
$instanceID = null;
unset($args[0], $args[1]);
$command = trim(implode(' ', $args));
if (!$command) {
\Yii::$app->system->error('Command to execute after obtaining process lock is missing.', ['Args' => $argsAll]);
}
if (file_exists('/etc/elasticbeanstalk/.aws-eb-system-initialized')) {
if ($awsEb = file_get_contents('/etc/elasticbeanstalk/.aws-eb-system-initialized')) {
$awsEb = json_decode($awsEb);
if (is_object($awsEb) && $awsEb->instance_id) {
$instanceID = $awsEb->instance_id;
}
}
}
$updateColumns = false;
$affectedRows = \Yii::$app->db->createCommand()->upsert('system_job_locks', [
'job_name' => $jobName,
'locked' => gmdate('Y-m-d H:i:s'),
'duration' => $durationMins,
'source' => $instanceID,
], $updateColumns)->execute();
if ($affectedRows == 0) {
$affectedRows = \Yii::$app->db->createCommand()->update('system_job_locks', [
'locked' => gmdate('Y-m-d H:i:s'),
'duration' => $durationMins,
'source' => $instanceID,
],
'job_name = :jobName AND DATE_ADD(locked, INTERVAL duration MINUTE) < NOW()', ['jobName' => $jobName]
)->execute();
if ($affectedRows == 0) {
exit;
}
}
$command = str_replace('StdOUT', '>', $command);
$command = str_replace('StdERR.ditto', '2>&1', $command);
$command = str_replace('StdERR', '2>', $command);
$command .= ' &';
$output = []; $exitcode = null;
exec($command, $output, $exitcode);
exit($exitcode);
}
นี่คือสคีมาฐานข้อมูลที่ฉันใช้:
CREATE TABLE `system_job_locks` (
`job_name` VARCHAR(50) NOT NULL,
`locked` DATETIME NOT NULL COMMENT 'UTC',
`duration` SMALLINT(5) UNSIGNED NOT NULL COMMENT 'Minutes',
`source` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`job_name`)
)