我用flock
每秒都有一个sms cronjob与我的服务器一起运行我的脚本被杀了异常,为什么我说这是异常?
有时,我的脚本运行并发送大约2千条短信没有任何问题
某个时候(现在),我的脚本运行一个新的批次,有173个短信,并且总是随机被杀
这是调度员
<?php
namespace MPN\Sms2Bundle\Service;
use Doctrine\ORM\EntityManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
use MPN\CRMBundle\Service\UserAwareService;
use MPN\Sms2Bundle\Service\Calculator;
use MPN\Sms2Bundle\Service\Renderer;
use MPN\Sms2Bundle\Manager\SettingManager;
use MPN\DataBundle\Entity\Contact\Contact;
use MPN\DataBundle\Entity\Contact\Phone as ContactPhone;
use MPN\Sms2Bundle\Entity\Sms;
use MPN\Sms2Bundle\Entity\SmsConstants;
use MPN\Sms2Bundle\Entity\Batch;
use MPN\Sms2Bundle\Entity\History;
use MPN\Sms2Bundle\SmsEvents;
use MPN\Sms2Bundle\Event\FailureEvent;
/**
* This class provides low-level methods for sending `sms`.
*
* @see \MPN\Sms2Bundle\Service\Sender::sendNow() for high-level method
*/
class Dispatcher extends UserAwareService
{
private $em;
private $eventDispatcher;
private $calculator;
private $renderer;
private $settingManager;
private $username;
private $password;
private $sender;
public function __construct(EntityManager $em, EventDispatcherInterface $eventDispatcher, SettingManager $settingManager, Calculator $calculator, Renderer $renderer, SecurityContextInterface $securityContext, $username, $password, $sender)
{
$this->em = $em;
$this->eventDispatcher = $eventDispatcher;
$this->settingManager = $settingManager;
$this->calculator = $calculator;
$this->renderer = $renderer;
$this->username = $username;
$this->password = $password;
$this->sender = $sender;
$this->setSecurityContext($securityContext);
}
/**
* Sends $sms to $contactPhone.
*
* You should check if credit is sufficient before sending $sms.
* This method ignores the contact's status, i.e. if it is soft-deleted.
*
* @see \MPN\Sms2Bundle\Service\Calculator::hasEnoughCreditForOneTime() for checking credit balance
* @param string|ContactPhone $contactPhone
* @return boolean|integer Credit spent or FALSE if failed to send.
*/
public function send(Sms $sms, $contactPhone)
{
if (is_string($contactPhone)) {
$mobile = $contactPhone;
$contact = null;
} else {
$mobile = $contactPhone->getNumber();
$contact = $contactPhone->getContact();
}
$content = $this->renderer->render($sms, $contact);
$credit = false;
if ($this->_send($mobile, $content))
$credit = $this->calculator->calculateCredit($sms, $contact);
return $credit;
}
/**
* Sends $sms to all filtered and non-deleted linked contact phones.
* Credits are *DEDUCTED* here.
*
* You should check if credit is sufficient to send $sms.
*
* @see \MPN\Sms2Bundle\Service\Calculator::hasEnoughCreditForOneTime() for checking credit balance
* @param \MPN\Sms2Bundle\Entity\Sms $sms
* @param boolean $andFlush
*/
public function sendToAll(Sms $sms, $andFlush = true)
{
$recipients = array();
if ($sms->getToAllContactTypes() || $sms->getToAllContactGroups() || $sms->getToAllContactPhones()) {
$contacts = $this->em->getRepository('MPN\DataBundle\Entity\Contact\Contact')->findBy(array(
'deleted' => false,
));
foreach ($contacts as $contact)
$recipients = array_merge($recipients, $contact->getMobilePhones());
} else {
$contactTypes = $sms->getContactTypes();
foreach ($contactTypes as $contactType)
$recipients = array_merge($recipients, $contactType->getMobilePhones());
$contactGroups = $sms->getContactGroups();
foreach ($contactGroups as $contactGroup)
$recipients = array_merge($recipients, $contactGroup->getMobilePhones());
$contactPhones = $sms->getContactPhones();
foreach ($contactPhones as $contactPhone)
$recipients[] = $contactPhone;
$company = $sms->getCompany();
if (null !== $company && $company->hasContacts()) {
$recipients = array_merge($recipients, $company->getMobilePhones());
}
}
$recipients = array_unique(array_merge($recipients, $sms->getGeneralContactsAsArray()));
// Create a Batch instance and *flush*
$batch = new Batch();
$batch->setDeliveredAt(new \DateTime());
$sms->addBatch($batch); // add batch increase sentCount by 1
$this->em->flush();
$failedContacts = array();
foreach ($recipients as $contactPhone) {
$isContactPhoneInstance = $contactPhone instanceof ContactPhone;
if ($isContactPhoneInstance) {
$contact = $contactPhone->getContact();
if (!$this->isOwner($contact)
|| $contact->isDeleted()
|| !$sms->testTargetContact($contact)) {
continue;
}
//Check if not mobile number, mean not start with 601, skip it
// if (substr($contact->getPhone(), 0, 3) != '601') {
// continue;
// }
}
$credit = $this->send($sms, $contactPhone);
print ".";
$isSuccessful = $credit !== false;
$history = new History();
if ($isContactPhoneInstance) {
$contact = $contactPhone->getContact();
$content = $this->renderer->render($sms, $contact);
$history
->setRecipientName($contact->getFullName())
->setRecipientNumber($contactPhone->getNumber())
;
} else {
$content = $this->renderer->render($sms);
$history
->setRecipientName('General Contact')
->setRecipientNumber($contactPhone)
;
}
// Notify listeners to handle this failure
if ($isContactPhoneInstance && !$isSuccessful && !in_array($contact, $failedContacts)) {
$event = new FailureEvent($sms, $contact, $content);
$this->eventDispatcher->dispatch(SmsEvents::FAILURE, $event);
// Record this contact so mail won't be sent more than one time
$failedContacts[] = $contact;
}
$history
->setContent($content)
->setCredit((int) $credit)
->setSuccess($isSuccessful)
;
$batch
->addHistory($history)
;
$this->em->flush();
// decrease the credit *now*
// failed to send messages cost 0 credit, so doesn't matter!
$this->settingManager->decreaseCredit($credit);
}
if ($andFlush)
$this->em->flush();
return $batch->getCredit();
}
/**
* Sends a message without logging any information.
*
* @param string $mobile
* @param string $content
*
* @return bool
*/
public function quickSend($mobile, $content)
{
return $this->_send($mobile, $content);
}
/**
* Actually sends the message out.
*
* @param string $mobile
* @param string $content
*
* @return bool
*/
private function _send($mobile, $content)
{
$url = $this->buildUrl($mobile, $content);
$response = @file_get_contents($url);
return !!preg_match('/^1701:\d+$/', $response);
}
private function buildUrl($mobile, $content)
{
// $url = 'http://www.example.com/websmsapi/isendsms.aspx?username=%s&password=%s&sender=%s&type=%d&mobile=%s&message=%s';
// Fake sms server, record all the record only
$url = 'http://example.my/sendsms.php?mobile=%s&message=%s';
$encodedContent = $this->renderer->encode($content);
if ($this->renderer->isUnicodeContent($content))
$type = 3;
else
$type = 1;
// return sprintf(
// $url,
// $this->username,
// $this->password,
// $this->sender,
// $type,
// $mobile,
// $encodedContent
// );
return sprintf(
$url, $mobile, $encodedContent
);
}
}
这是发送命令
<?php
namespace MPN\Sms2Bundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use MPN\Sms2Bundle\Entity\SmsConstants;
use MPN\Sms2Bundle\SmsEvents;
class SendCommand extends ContainerAwareCommand
{
protected $preEventDispatched = false;
protected function configure()
{
$this
->setName('sms:send')
->setDescription('Send SMS')
->addArgument('id', InputArgument::OPTIONAL, 'Sms ID')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
set_time_limit(1800);
$container = $this->getContainer();
$eventDispatcher = $container->get('event_dispatcher');
$em = $container->get('doctrine')->getManager();
$repo = $em->getRepository('MPNSms2Bundle:Sms');
$queryBuilder = $repo->createQueryBuilder('s');
$calculator = $container->get('mpn_sms2.calculator');
$dispatcher = $container->get('mpn_sms2.dispatcher');
$id = $input->getArgument('id');
// In progress status and scheduled to send records
$queryBuilder
->where('s.status = :status')->setParameter('status', SmsConstants::STATUS_IN_PROGRESS)
->andWhere('s.scheduledAt <= :now')->setParameter('now', new \DateTime())
->andWhere('s.sendCount > s.sentCount')
->orderBy('s.createdAt', 'ASC')
;
$messages = array();
if ($id) {
$message = $queryBuilder
->andWhere('s.id = :id')->setParameter('id', $id)
->getQuery()
->getOneOrNullResult()
;
if ($message)
$messages[] = $message;
} else {
$messages = $queryBuilder->getQuery()->getResult();
}
$spentCredit = 0;
foreach ($messages as $sms) {
if ($sms->shouldSendNow() && $calculator->hasEnoughCreditForOneTime($sms)) {
// Pre process event
if (false === $this->preEventDispatched) {
$eventDispatcher->dispatch(SmsEvents::PRE_PROCESS);
$this->preEventDispatched = true;
}
// credits are deducted in dispatcher
$credit = $dispatcher->sendToAll($sms, false);
$spentCredit += $credit;
$em->flush();
}
}
$output->writeln(sprintf(
'Spent %d credit(s) at %s',
$spentCredit,
date('d-m-Y h:i:s a', time())
));
// Post send event
$eventDispatcher->dispatch(SmsEvents::POST_PROCESS);
}
}
在我的php设置中,我有
max_execution_time = 480
max_input_time = 0
max_input_vars = 1000
memory_limit = 4096M
这里是cronjob
/usr/bin/env php /home/ecocrm/public_html/control/app/console sms:daemon -e prod >> /tmp/ecocrm_sms_daemon.log 2>&1
我将msg保存在日志中,所以我可以回来看看
在我的调度员中,每次成功(或失败)
打印“。”;
我检查了我的日志文件,有.......... Killed
有时.......................已经杀了
我怎样才能检查杀人的原因?任何我应该如何修复或调试它,错误信息是如此简单,只是 Killed ,没有其他的消息让我检查它...如果你想了解更多有关源代码的信息,请告诉我,非常感谢谁为此提供帮助,首先感谢
**update 1:**
在我google一段时间之后,很多人说它错误因为内存泄漏,所以我添加了这个
print(sprintf('Memory usage (currently) %dKB/ (max) %dKB', round(memory_get_usage(true) / 1024), memory_get_peak_usage(true) / 1024));print("\r\n");
在调度员 foreach($ recipients as $ contactPhone){
这是结果
Memory usage (currently) 114432KB/ (max) 114688KB
Memory usage (currently) 114432KB/ (max) 114688KB
Memory usage (currently) 114432KB/ (max) 114688KB
Memory usage (currently) 114432KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB
Memory usage (currently) 114688KB/ (max) 114688KB