gearman 实例一枚

有问题多看日志

gearman.log和gearmand.log


* related error messages: http://tech-lightnight.blogspot.jp/2013/04/start-with-gearman.html

* useful information:

https://groups.google.com/forum/#!topic/gearman/2LLx2iq1uhA

http://stackoverflow.com/questions/16815420/when-php-gearman-client-fails-to-connect-to-the-server-i-get-the-same-code-as-wh



start gearman : gearmand -d

stop gearman: gearadmin --shutdown (it seems that it doesn't work)

other commands: gearadmin --status  --workers

watch -n 1 "(echo status; sleep 0.1) | nc 127.0.0.1 4730"

----------------

有一个问题一直没有解决:

$ gearmand -d

$ command for starting gearman worker

$ waiting for gearman client to run tasks

开始时运行正常,client添加的任务都可以被worker及时处理,但是过了一段时间(可能是几天)后,client再发任务,worker就只能收到一部分或收不到任务。

-----------------


下面是一段调通的gearman程序:

1. GearmanClient

从数据库中取出一堆人checkins,将这堆人分成(小于等于)20组,然后为GearmanClient添加(小于等于)20个后台任务。

public function action_send_notification() {
        
        $event_id = Arr::get($_GET, 'event_id');
        $is_drill = Arr::get($_GET, 'is_drill');
    
        $sql = 'SELECT CheckIn.id as checkin_id, User.id as user_id, User.email, User.phonenumber, User.subscription, User.topicarn from CheckIn, User where CheckIn.eventID = :event_id and CheckIn.EmailStatus = 0 and CheckIn.SMSStatus = 0 and CheckIn.UserID = User.id';  
        $query = DB::query(Database::SELECT, $sql);  
        $query->param(':event_id', $event_id);  
        $checkins = $query->execute()->as_array(); 
        
        if (count($checkins) > 0) {
            $task_arr = $this->array_split($checkins, 20);

            try {
                $gmclient = new GearmanClient();
                $gmclient->addServer();
      
                for ($i=0; $i < count($task_arr); $i++) { 
                    $gmclient->addTaskBackground("sendmail", json_encode($task_arr[$i]));
                }

                $gmclient->runTasks();
            } catch (Exception $e) {
                $response_data['error'] = $e->getMessage();
            }
        }
        $response_data['status'] = 'client success';
        $this->response->body(json_encode($response_data));
    }

    private function array_split($array, $parts) {
        return array_chunk($array, ceil(count($array) / $parts));
    }



2. GearmanWorker

将worker设计为常驻进程,在父进程中fork四个子进程,每个子进程启动一个worker,不停地等待并处理任务。

一旦worker不能正常工作,则所在子进程exit,父进程中的wait将收到子进程退出的通知,于是重新fork一个子进程并启动补上一个worker。

</pre><p><pre name="code" class="php"><?php defined('SYSPATH') or die('No direct script access.');

    

class Task_Processmail extends Minion_Task {
    
    protected function _execute(array $params)
    {
        for ($i=0; $i < 4; $i++) { 
            $pid = pcntl_fork();
            if (0 == $pid) {      
                $gmworker = new GearmanWorker();
                $gmworker->addServer();
                $gmworker->addFunction("sendmail", "sendmail_fn");
                while (1) {
                    $gmworker->work();
                    if($gmworker->returnCode() != GEARMAN_SUCCESS)
                        break;
                }
                exit();
            } 
        }
    
        // 父进程
        while(TRUE) {
            $pid = pcntl_wait($status);
            
            // 重启关闭的子进程
            posix_kill($pid, SIGKILL);
            $pid = pcntl_fork();
            if (0 == $pid) {
                $gmworker = new GearmanWorker();
                $gmworker->addServer();
                $gmworker->addFunction("sendmail", "sendmail_fn");
                while (1) {
                    $gmworker->work();
                    if($gmworker->returnCode() != GEARMAN_SUCCESS)
                        break;
                }
                exit();
            } 
        }
    }

}

function sendmail_fn($job) {
    $workload = json_decode($job->workload(), true);
    // print_r($workload);

    foreach ($workload as $key => $value) {
        // $value = $workload;
        $checkin;
        try {
            $checkin = ORM::factory('Checkin')->where('id', '=', $value['checkin_id'])->find();
        } catch (Exception $e) {
            echo $e->getMessage();
            continue;
        }
 

        if ($checkin->loaded()) {  
            try {
                $content = array();
                $content['subject'] = "Emergency ".(!$value['is_drill'] ? "Situation Now" : "Drill Now");
                $content['content'] = "There is an emergency ".(!$value['is_drill'] ? "situation" : "drill").". Please click <a href=\"http://52.22.36.108/pinpoint/index.php/checkin?eventID=".$value['event_id']."&userID=".$value['user_id']."\">here</a> to checkin with Pinpoint.";

                $email = array();
                $email[] = $value['email'];
                AmazonSMS::sendmail($email, $content);

                //change status
                $checkin->EmailStatus = true;
                
                echo "send email ok.\n";
            } catch (Exception $e) {
                LOG::Instance()->add(Log::ERROR, 'Could not send email to :'.$value['email']);

                //change status
                $checkin->EmailStatus = false;

                echo "**send email fail: ";
                echo $e->getMessage();
            }              
        

            if (!empty($value['phonenumber']) && strlen($value['phonenumber']) > 8) {
                if (!empty($value['subscription']) && strlen($value['subscription'])>0) {
                    // LOG::Instance()->add(Log::INFO, 'SMS sent to :'.$value['phonenumber'], $value);
                    try {
                        AmazonSMS::sendMessage(array(
                            'arn' => $value['topicarn'],
                            'message' => "There is an emergency ".(!$Drill ? "situation" : "drill").". Please checkin with Pinpoint http://52.22.36.108/pinpoint/index.php/checkin?eventID=$event_id&userID=".$value['user_id']
                        ));

                        //change status
                        $checkin->SMSStatus = true;
                        
                    } catch (Exception $e) {
                        // LOG::Instance()->add(Log::ERROR, 'Could not send sms to :'.$value['phonenumber'], $e);

                        //change status
                        $checkin->SMSStatus = false;
                    }
                }
            }

            $checkin->save();
        } else {
            echo "ORM load fail";
        }
    }
}


 

下面的两幅图是间隔几个小时的两次进程查询:





可见,第四列数据(进程号)已经改变了,说明在此期间有进程exit并重新fork了新进程。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值