매분 실행하도록 cronjob / task를 설정하는 방법이 있는지 알고 싶습니다. 현재 모든 인스턴스에서이 작업을 실행할 수 있습니다.
이것은 성공하지 않고 구성 파일에서 시도한 것입니다.
container_commands:
01cronjobs:
command: echo "*/1 * * * * root php /etc/httpd/myscript.php"
이것이 올바른 방법인지 잘 모르겠습니다.
어떤 아이디어?
매분 실행하도록 cronjob / task를 설정하는 방법이 있는지 알고 싶습니다. 현재 모든 인스턴스에서이 작업을 실행할 수 있습니다.
이것은 성공하지 않고 구성 파일에서 시도한 것입니다.
container_commands:
01cronjobs:
command: echo "*/1 * * * * root php /etc/httpd/myscript.php"
이것이 올바른 방법인지 잘 모르겠습니다.
어떤 아이디어?
답변:
.ebextensions라는 애플리케이션의 루트에 폴더가 아직없는 경우 생성합니다. 그런 다음 .ebextensions 폴더 내에 구성 파일을 생성합니다. 설명을 위해 example.config를 사용하겠습니다. 그런 다음 이것을 example.config에 추가하십시오.
container_commands:
01_some_cron_job:
command: "cat .ebextensions/some_cron_job.txt > /etc/cron.d/some_cron_job && chmod 644 /etc/cron.d/some_cron_job"
leader_only: true
Elastic Beanstalk에 대한 YAML 구성 파일입니다. 이것을 텍스트 편집기에 복사 할 때 텍스트 편집기가 탭 대신 공백을 사용하는지 확인하십시오. 그렇지 않으면 이것을 EB로 푸시 할 때 YAML 오류가 발생합니다.
그래서 이것이하는 일은 01_some_cron_job이라는 명령을 만드는 것입니다. 명령은 알파벳 순서로 실행되므로 01은 첫 번째 명령으로 실행되도록합니다.
그런 다음이 명령은 some_cron_job.txt라는 파일의 내용을 가져와 /etc/cron.d의 some_cron_job이라는 파일에 추가합니다.
그런 다음 명령은 /etc/cron.d/some_cron_job 파일에 대한 권한을 변경합니다.
leader_only 키는 명령이 리더로 간주되는 ec2 인스턴스에서만 실행되도록합니다. 모든 ec2 인스턴스에서 실행하는 대신 실행 중일 수 있습니다.
그런 다음 .ebextensions 폴더 내에 some_cron_job.txt라는 파일을 생성합니다. 이 파일에 크론 작업을 배치합니다.
예를 들면 다음과 같습니다.
# The newline at the end of this file is extremely important. Cron won't run without it.
* * * * * root /usr/bin/php some-php-script-here > /dev/null
따라서이 크론 작업은 루트 사용자로 매일 매시간 1 분마다 실행되고 / dev / null에 대한 출력을 버립니다. / usr / bin / php는 php의 경로입니다. 그런 다음 some-php-script-here를 php 파일의 경로로 바꿉니다. 이것은 분명히 cron 작업이 PHP 파일을 실행해야한다고 가정합니다.
또한 some_cron_job.txt 파일에 주석이 말한 것처럼 파일 끝에 개행 문자가 있는지 확인하십시오. 그렇지 않으면 cron이 실행되지 않습니다.
업데이트 : Elastic Beanstalk가 인스턴스를 확장 할 때이 솔루션에 문제가 있습니다. 예를 들어 cron 작업이 실행중인 인스턴스가 하나 있다고 가정 해 보겠습니다. 트래픽이 증가하여 Elastic Beanstalk가 최대 2 개의 인스턴스로 확장합니다. leader_only는 두 인스턴스간에 하나의 크론 작업 만 실행하도록합니다. 트래픽이 감소하고 Elastic Beanstalk가 사용자를 하나의 인스턴스로 축소합니다. 그러나 두 번째 인스턴스를 종료하는 대신 Elastic Beanstalk는 리더였던 첫 번째 인스턴스를 종료합니다. 이제 종료 된 첫 번째 인스턴스에서만 실행중인 크론 작업이 실행되지 않습니다. 아래 설명을 참조하십시오.
업데이트 2 : 아래 설명에서이를 명확히합니다. AWS는 이제 자동 인스턴스 종료로부터 보호합니다. 리더 인스턴스에서 활성화하기 만하면됩니다. – Nicolás Arévalo '16 10 월 28 일 9:23에
01_some_cron_job
에 02_some_cron_job
및 추가 01_remove_cron_jobs
다음과 : command: "rm /etc/cron.d/cron_jobs || exit 0"
. 이렇게하면 모든 배포 후에 리더 만 cron_jobs
파일 을 갖게 됩니다. 리더가 변경되면 재배포 만하면 크론이 다시 실행되도록 수정됩니다.
현재 문서에 따르면 소위 작업자 계층 에서 주기적인 작업을 실행할 수 있습니다.
문서 인용 :
AWS Elastic Beanstalk는 컨테이너 이름에 "v1.2.0"이 포함 된 솔루션 스택으로 사전 정의 된 구성을 실행하는 환경에서 작업자 환경 계층에 대한 주기적 작업을 지원합니다. 새 환경을 만들어야합니다.
또한 흥미로운 부분은 cron.yaml에 대한 부분입니다 .
주기적 작업을 호출하려면 애플리케이션 소스 번들에 루트 수준의 cron.yaml 파일이 포함되어야합니다. 파일에는 예약하려는 정기 작업에 대한 정보가 포함되어야합니다. 표준 crontab 구문을 사용하여이 정보를 지정하십시오.
업데이트 : 우리는이 작업을 할 수있었습니다. 다음은 우리의 경험 (Node.js 플랫폼)에서 얻은 몇 가지 중요한 문제점입니다.
eb ssh
)하고 cat /var/log/aws-sqsd/default.log
. 로보고되어야합니다 aws-sqsd 2.0 (2015-02-18)
. 2.0 버전이없는 경우 환경을 만들 때 문제가 발생하여 위에서 설명한대로 새 환경을 만들어야합니다.jamieb의 응답과 관련하여 비정상적으로 언급했듯이 'leader_only'속성을 사용하여 하나의 EC2 인스턴스 만 크론 작업을 실행하도록 할 수 있습니다.
http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html 에서 인용 한 내용 :
leader_only를 사용할 수 있습니다. 하나의 인스턴스가 Auto Scaling 그룹의 리더로 선택됩니다. leader_only 값이 true로 설정된 경우 명령은 리더로 표시된 인스턴스에서만 실행됩니다.
나는 내 eb에서 비슷한 것을 달성하려고 노력하고 있으므로 그것을 해결하면 내 게시물을 업데이트 할 것입니다.
최신 정보:
좋아, 이제 다음 eb 구성을 사용하여 작업하는 cronjob이 있습니다.
files:
"/tmp/cronjob" :
mode: "000777"
owner: ec2-user
group: ec2-user
content: |
# clear expired baskets
*/10 * * * * /usr/bin/wget -o /dev/null http://blah.elasticbeanstalk.com/basket/purge > $HOME/basket_purge.log 2>&1
# clean up files created by above cronjob
30 23 * * * rm $HOME/purge*
encoding: plain
container_commands:
purge_basket:
command: crontab /tmp/cronjob
leader_only: true
commands:
delete_cronjob_file:
command: rm /tmp/cronjob
기본적으로 cronjobs로 임시 파일을 만든 다음 임시 파일에서 읽도록 crontab을 설정 한 다음 나중에 임시 파일을 삭제합니다. 도움이 되었기를 바랍니다.
위에서 언급했듯이 crontab 구성 설정의 근본적인 결함은 배포시에만 발생한다는 것입니다. 클러스터가 자동으로 확장 된 다음 다시 축소됨에 따라 첫 번째 서버를 끄는 것이 좋습니다. 또한 장애 조치가 없을 것입니다.
몇 가지 조사를 한 다음 AWS 계정 전문가와상의하여 아이디어를 되돌리고 제가 생각 해낸 솔루션을 검증했습니다. OpsWorks를 사용하면 집을 사용하여 파리를 죽이는 것과 비슷하지만 이 작업을 수행 할 수 있습니다 . Task Runner와 함께 Data Pipeline 을 사용할 수도 있지만 실행할 수있는 스크립트의 기능이 제한되어 있으므로 전체 코드 기반에 액세스하여 PHP 스크립트를 실행할 수 있어야했습니다. ElasticBeanstalk 클러스터 외부에 EC2 인스턴스를 전용 할 수도 있지만, 그런 다음 다시 장애 조치가 없습니다.
그래서 여기에 내가 생각해 낸 것이 있는데, 이것은 분명히 (AWS 담당자가 언급했듯이) 비정상적이며 해킹으로 간주 될 수 있지만 작동하고 장애 조치로 견고합니다. 원하는 언어로 동일한 방법을 수행 할 수 있지만 SDK를 사용하여 코딩 솔루션을 선택했습니다.이 솔루션은 PHP로 보여 드리겠습니다.
// contains the values for variables used (key, secret, env)
require_once('cron_config.inc');
// Load the AWS PHP SDK to connection to ElasticBeanstalk
use Aws\ElasticBeanstalk\ElasticBeanstalkClient;
$client = ElasticBeanstalkClient::factory(array(
'key' => AWS_KEY,
'secret' => AWS_SECRET,
'profile' => 'your_profile',
'region' => 'us-east-1'
));
$result = $client->describeEnvironmentResources(array(
'EnvironmentName' => AWS_ENV
));
if (php_uname('n') != $result['EnvironmentResources']['Instances'][0]['Id']) {
die("Not the primary EC2 instance\n");
}
따라서이 과정과 작동 방식을 살펴보면 일반적으로 모든 EC2 인스턴스에서 하듯이 crontab에서 스크립트를 호출합니다. 각 스크립트는 처음에 이것을 포함 (또는 내가 사용하는 각각에 대해 단일 파일을 포함)하여 ElasticBeanstalk 객체를 설정하고 모든 인스턴스의 목록을 검색합니다. 목록의 첫 번째 서버 만 사용하고 자신과 일치하는지 확인합니다. 일치하는 경우 계속 진행되고 그렇지 않으면 종료되고 닫힙니다. 확인한 결과 반환 된 목록이 일관된 것 같습니다. 기술적으로는 각 인스턴스가 예약 된 크론을 실행하기 때문에 1 분 정도만 일관성이 있으면됩니다. 변경되면 문제가되지 않습니다. 다시 한 번 작은 창에만 관련이 있기 때문입니다.
이것은 결코 우아하지는 않지만 추가 서비스로 비용을 늘리거나 전용 EC2 인스턴스를 가져야하는 것이 아니고 장애 발생시 장애 조치가 필요한 특정 요구 사항에 적합했습니다. cron 스크립트는 SQS에 배치되는 유지 관리 스크립트를 실행하고 클러스터의 각 서버는 실행을 돕습니다. 적어도 이것은 귀하의 필요에 맞는 경우 대체 옵션을 제공 할 수 있습니다.
-데이비
$instanceId = file_get_contents("http://instance-data/latest/meta-data/instance-id");
다음을 사용했습니다. 그런 다음 $ instanceId var를 사용하여 비교를 수행합니다.
저는 AWS 지원 에이전트와 이야기를 나눴으며 이것이 저를 위해 작동하게 된 방법입니다. 2015 년 솔루션 :
your_file_name.config를 사용하여 .ebextensions 디렉터리에 파일을 생성합니다. 구성 파일 입력에서 :
파일 : "/etc/cron.d/cron_example": 모드 : "000644" 소유자 : 루트 그룹 : 루트 내용 : | * * * * * 루트 /usr/local/bin/cron_example.sh "/usr/local/bin/cron_example.sh": 모드 : "000755" 소유자 : 루트 그룹 : 루트 내용 : | #! / bin / bash /usr/local/bin/test_cron.sh || 출구 echo ""`date` >> /tmp/cron_example.log에 실행중인 크론 # 이제 하나의 인스턴스에서만 실행되어야하는 작업을 수행합니다 ... "/usr/local/bin/test_cron.sh": 모드 : "000755" 소유자 : 루트 그룹 : 루트 내용 : | #! / bin / bash METADATA = / opt / aws / bin / ec2-metadata INSTANCE_ID =`$ METADATA -i | awk '{print $ 2}'` 지역 =`$ METADATA -z | awk '{print substr ($ 2, 0, length ($ 2) -1)}'` # Auto Scaling 그룹 이름을 찾습니다. ASG = ʻaws ec2 describe-tags --filters "Name = resource-id, Values = $ INSTANCE_ID"\ --region $ REGION-출력 텍스트 | awk '/ aws : autoscaling : groupName / {print $ 5}'` # 그룹에서 첫 번째 인스턴스 찾기 FIRST = ʻaws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $ ASG \ --region $ REGION-출력 텍스트 | awk '/ InService $ / {print $ 4}'| 정렬 | 머리 -1` # 동일한 지 테스트합니다. [ "$ FIRST"= "$ INSTANCE_ID"] 명령 : rm_old_cron : 명령 : "rm * .bak" cwd : "/etc/cron.d" ignoreErrors : true
이 솔루션에는 두 가지 단점이 있습니다.
해결 방법 :
경고:
기본 beanstalk 역할을 사용하는 경우 IAM 역할을 설정할 필요가 없습니다.
Rails를 사용하는 경우 every-elasticbeanstalk gem을 사용할 수 있습니다 . 이를 통해 모든 인스턴스 또는 하나에서만 크론 작업을 실행할 수 있습니다. 매분마다 "리더"인스턴스가 하나만 있는지 확인하고 서버가 없으면 자동으로 한 서버를 "리더"로 승격합니다. Elastic Beanstalk는 배포 중 리더의 개념 만 가지고 있으며 확장하는 동안 언제든지 인스턴스를 종료 할 수 있기 때문에 필요합니다.
업데이트 AWS OpsWorks를 사용하도록 전환했으며 더 이상이 gem을 유지하지 않습니다. Elastic Beanstalk의 기본에서 사용할 수있는 것보다 더 많은 기능이 필요한 경우 OpsWorks로 전환하는 것이 좋습니다.
Elastic Beanstalk에서 크론 작업을 실행하고 싶지는 않습니다. 여러 응용 프로그램 인스턴스가 있으므로 경합 상태 및 기타 이상한 문제가 발생할 수 있습니다. 나는 최근에 이것에 대해 블로그를 썼다 (페이지 아래 네 번째 또는 다섯 번째 팁). 짧은 버전 : 애플리케이션에 따라 SQS와 같은 작업 대기열 또는 iron.io 와 같은 타사 솔루션을 사용 합니다 .
구성하는 데 2 분이면 충분합니다.
laravel-aws-worker 설치
composer require dusterio/laravel-aws-worker
cron.yaml을 루트 폴더에 추가하십시오.
애플리케이션의 루트 폴더에 cron.yaml을 추가합니다 (저장소의 일부이거나 EB에 배포하기 직전에이 파일을 추가 할 수 있습니다. 중요한 것은이 파일이 배포시 존재한다는 것입니다).
version: 1
cron:
- name: "schedule"
url: "/worker/schedule"
schedule: "* * * * *"
App\Console\Kernel
이제 모든 작업 이 실행됩니다.
자세한 지침 및 설명 : https://github.com/dusterio/laravel-aws-worker
Laravel 내부에서 작업을 작성하는 방법 : https://laravel.com/docs/5.4/scheduling
files
대신 다음을 사용하는 더 읽기 쉬운 솔루션 container_commands
:
파일 : "/etc/cron.d/my_cron": 모드 : "000644" 소유자 : 루트 그룹 : 루트 내용 : | # 기본 이메일 주소 재정의 MAILTO = "example@gmail.com" # 5 분마다 Symfony 명령 실행 (ec2-user로) * / 10 * * * * ec2-user / usr / bin / php / var / app / current / app / console do : something 인코딩 : 일반 명령 : # Elastic Beanstalk에서 생성 한 백업 파일 삭제 clear_cron_backup : 명령 : rm -f /etc/cron.d/watson.bak
형식은 명령을 실행할 사용자를 지정한다는 점에서 일반적인 crontab 형식과 다릅니다.
2018 년 기부금 1 센트
올바른 방법 ( django/python
및 django_crontab
앱 사용)은 다음 과 같습니다.
.ebextensions
폴더 안에 98_cron.config
다음 과 같은 파일을 만듭니다 .
files:
"/tmp/98_create_cron.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/sh
cd /
sudo /opt/python/run/venv/bin/python /opt/python/current/app/manage.py crontab remove > /home/ec2-user/remove11.txt
sudo /opt/python/run/venv/bin/python /opt/python/current/app/manage.py crontab add > /home/ec2-user/add11.txt
container_commands:
98crontab:
command: "mv /tmp/98_create_cron.sh /opt/elasticbeanstalk/hooks/appdeploy/post && chmod 774 /opt/elasticbeanstalk/hooks/appdeploy/post/98_create_cron.sh"
leader_only: true
container_commands
대신 해야합니다commands
누군가 새로운 리더가 발생했을 때 leader_only 자동 확장 문제에 대해 궁금해했습니다. 댓글에 응답하는 방법을 알아낼 수없는 것 같지만 다음 링크를 참조하세요. http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling- 환경/
Amazon의 최신 예제가 가장 쉽고 효율적입니다 (주기적 작업).
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html
크론 작업을 실행하기 위해 별도의 작업자 계층을 생성합니다. cron.yaml 파일을 만들고 루트 폴더에 저장합니다. 내가 가진 한 가지 문제는 (cron이 실행되지 않는 것 같았던 후) 내 CodePipeline에 dynamodb 수정을 수행 할 권한이 없다는 사실입니다. 이를 기반으로 IAM-> 역할-> yourpipeline 아래에 FullDynamoDB 액세스를 추가하고 (탄력적 인 Beantalk) 재배포 한 후 완벽하게 작동했습니다.
그래서 우리는 한동안 이것으로 어려움을 겪고 있었고 AWS 담당자와 약간의 논의를 거쳐 마침내 최고의 솔루션이라고 생각하는 것을 생각해 냈습니다.
cron.yaml과 함께 작업자 계층을 사용하는 것이 가장 쉬운 해결 방법입니다. 그러나 문서에서 명확하지 않은 것은 실제로 작업을 실행하는 데 사용하는 SQS 대기열 의 끝에 작업을 배치한다는 것 입니다. 크론 작업이 시간에 민감한 경우 (많은 경우) 대기열 크기에 따라 다르기 때문에 허용되지 않습니다. 한 가지 옵션은 cron 작업을 실행하기 위해 완전히 별도의 환경을 사용하는 것이지만 이는 과잉이라고 생각합니다.
목록의 첫 번째 인스턴스인지 확인하는 것과 같은 다른 옵션 중 일부도 이상적이지 않습니다. 현재 첫 번째 인스턴스가 종료되는 중이면 어떻게됩니까?
인스턴스 보호에도 문제가 발생할 수 있습니다. 인스턴스가 잠기거나 고정되면 어떻게됩니까?
이해해야 할 중요한 것은 AWS 자체에서 cron.yaml 기능을 관리하는 방법입니다. Dynamo 테이블을 사용하여 "리더 선택"을 처리하는 SQS 데몬이 있습니다. 이 테이블에 자주 쓰며 현재 리더가 잠시 동안 글을 쓰지 않으면 다음 인스턴스가 리더로 이어집니다. 이것은 데몬이 작업을 SQS 대기열로 실행할 인스턴스를 결정하는 방법입니다.
우리는 우리 자신의 기능을 다시 작성하려고하지 않고 기존 기능의 용도를 변경할 수 있습니다. 여기에서 전체 솔루션을 볼 수 있습니다 : https://gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27
Ruby에 있지만 AWS SDK가있는 다른 언어에 쉽게 적용 할 수 있습니다. 기본적으로 현재 리더를 확인한 다음 상태를 확인하여 상태가 양호한 지 확인합니다. 양호한 상태의 현재 리더가있을 때까지 반복되며 현재 인스턴스가 리더 인 경우 작업을 실행합니다.
축소시 Auto Scaling에서 특정 인스턴스를 종료 할 수 있는지 여부를 제어하려면 인스턴스 보호를 사용하십시오. Auto Scaling 그룹 또는 개별 Auto Scaling 인스턴스에서 인스턴스 보호 설정을 활성화 할 수 있습니다. Auto Scaling에서 인스턴스를 시작할 때 인스턴스는 Auto Scaling 그룹의 인스턴스 보호 설정을 상속합니다. Auto Scaling 그룹 또는 Auto Scaling 인스턴스에 대한 인스턴스 보호 설정은 언제든지 변경할 수 있습니다.
여기 PHP에서이 작업을 수행하려는 경우 수정 사항이 있습니다. 이렇게 작동하려면 .ebextensions 폴더에 cronjob.config가 필요합니다.
files:
"/etc/cron.d/my_cron":
mode: "000644"
owner: root
group: root
content: |
empty stuff
encoding: plain
commands:
01_clear_cron_backup:
command: "rm -f /etc/cron.d/*.bak"
02_remove_content:
command: "sudo sed -i 's/empty stuff//g' /etc/cron.d/my_cron"
container_commands:
adding_cron:
command: "echo '* * * * * ec2-user . /opt/elasticbeanstalk/support/envvars && /usr/bin/php /var/app/current/index.php cron sendemail > /tmp/sendemail.log 2>&1' > /etc/cron.d/my_cron"
leader_only: true
envvars는 파일에 대한 환경 변수를 가져옵니다. 위와 같이 tmp / sendemail.log에서 출력을 디버깅 할 수 있습니다.
이것이 우리를 확실히 도왔던 누군가에게 도움이되기를 바랍니다!
user1599237 의 답변 원칙에 따라 cron 작업이 모든 인스턴스에서 실행되도록 한 다음 대신 작업의 시작 부분에서 실행 허용 여부를 결정하고 다른 솔루션을 만들었습니다.
실행중인 인스턴스를보고 (그리고 AWS 키와 암호를 저장해야하는) 대신 모든 인스턴스에서 이미 연결중인 MySQL 데이터베이스를 사용하고 있습니다.
단점은없고 장점 만 있습니다.
또는 일반적으로 공유되는 파일 시스템 (예 : AWS EFS)을 사용할 수도 있습니다. 데이터베이스 대신 NFS 프로토콜을 통한 을 .
다음 솔루션은 PHP 프레임 워크 Yii 내에서 생성 되지만 다른 프레임 워크 및 언어에 쉽게 적용 할 수 있습니다. 또한 예외 처리기 Yii::$app->system
는 내 자신의 모듈입니다. 사용중인 것으로 교체하십시오.
/**
* Obtain an exclusive lock to ensure only one instance or worker executes a job
*
* Examples:
*
* `php /var/app/current/yii process/lock 60 empty-trash php /var/app/current/yii maintenance/empty-trash`
* `php /var/app/current/yii process/lock 60 empty-trash php /var/app/current/yii maintenance/empty-trash StdOUT./test.log`
* `php /var/app/current/yii process/lock 60 "empty trash" php /var/app/current/yii maintenance/empty-trash StdOUT./test.log StdERR.ditto`
* `php /var/app/current/yii process/lock 60 "empty trash" php /var/app/current/yii maintenance/empty-trash StdOUT./output.log StdERR./error.log`
*
* Arguments are understood as follows:
* - First: Duration of the lock in minutes
* - Second: Job name (surround with quotes if it contains spaces)
* - The rest: Command to execute. Instead of writing `>` and `2>` for redirecting output you need to write `StdOUT` and `StdERR` respectively. To redirect stderr to stdout write `StdERR.ditto`.
*
* Command will be executed in the background. If determined that it should not be executed the script will terminate silently.
*/
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 using AWS Elastic Beanstalk retrieve the instance ID
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;
}
}
}
// Obtain lock
$updateColumns = false; //do nothing if record already exists
$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();
// The SQL generated: INSERT INTO system_job_locks (job_name, locked, duration, source) VALUES ('some-name', '2019-04-22 17:24:39', 60, 'i-HmkDAZ9S5G5G') ON DUPLICATE KEY UPDATE job_name = job_name
if ($affectedRows == 0) {
// record already exists, check if lock has expired
$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();
// The SQL generated: UPDATE system_job_locks SET locked = '2019-04-22 17:24:39', duration = 60, source = 'i-HmkDAZ9S5G5G' WHERE job_name = 'clean-trash' AND DATE_ADD(locked, INTERVAL duration MINUTE) < NOW()
if ($affectedRows == 0) {
// We could not obtain a lock (since another process already has it) so do not execute the command
exit;
}
}
// Handle redirection of stdout and stderr
$command = str_replace('StdOUT', '>', $command);
$command = str_replace('StdERR.ditto', '2>&1', $command);
$command = str_replace('StdERR', '2>', $command);
// Execute the command as a background process so we can exit the current process
$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`)
)