PHP异步方法调用Yii框架 [英] PHP Asynchronous Method Call In The Yii Framework

查看:144
本文介绍了PHP异步方法调用Yii框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题



我想知道是否可以从其中一个动作异步调用Yii控制器方法,而该动作呈现一个视图,使该方法完成长时间的运行。我喜欢做如下面的代码,我不需要从 my_long_running_func 返回一个结果。

  public function actionCreate(){
$ model = new Vacancies;
if(isset($ _ POST ['Vacancies'])){
$ model-> setAttributes($ _ POST ['Vacancies']);
$ model-> save();
//我希望:)
call_user_func_async('my_long_running_func',$ model);
}
$ this-> render('create',array('model'=> $ model));
}



问题



我试图在Yii写一个控制器行动,发布一个空缺,并通知有兴趣的用户的帖子。问题是执行通知查询需要很长时间。



现在我正在寻找一种异步运行查询的方法,以便海报将其回复看作在C#代理或事件类似C#代理或事件的方式下,查询在后台运行时,尽可能少的时间。



我googled的解决方案执行异步请求在控制器动作的过程中,我所要做的就是以异步方式运行控制器的方法,并且动作必须等待直到请求 em>已完成。



尝试



我尝试了以下方法,但查询对我来说仍然很慢测试数据约为1500个用户。




  • Yii ActiveRecord



    <$ p $ ($ vacancy-> is_active == 1){
    $ url = Yii :: app() - > createUrl( '空位/视图',阵列( 'ID'=> $模型 - > ID));
    $ trainees = YumUser :: getUsersByRole('Trainees');
    if($ trainees!= null){
    foreach($ trainees as $ trainee){
    $ message = new YumMessage;
    $ message-> from_user_id = Yii :: app() - > user-> id;
    $ message-> title ='空缺通知:'.date('M j,Y');
    $ message-> message =新的空缺已发布在< a href ='{$ url}'> {$ url}< / a> ;.
    $ message-> to_user_id = $ trainee-> id;
    $ message-> save();
    }
    }
    }
    }


  • p> Yii数据访问对象

      if($ vacancy-> save()){
    if($ vacancy - > is_active == 1){
    $ url = Yii :: app() - > createAbsoluteUrl('vacancies / view',array('id'=> $ model-> id));
    $ trainee_ids = Yii :: app() - > db-> createCommand() - > select('user_id') - > from('trainee') - > queryColumn();
    $ fid = Yii :: app() - > user-> id;
    $ msg =新的空缺已发布在< a href ='{$ url}'> {$ url}< / a> ;.
    $ ts = time();
    $ tt ='空缺通知:'.date('M j,Y');
    if($ trainee_ids!= null){
    foreach($ trainee_ids as $ trainee_id){
    Yii :: app() - > db-> createCommand()
    - >插入( '信息',阵列( '时间戳'=> $ TS, 'from_user_id'=> $ FID, 'to_user_id'=> $ TID, '标题'=> $ TT, '消息' => $ MSG));
    }
    }
    }
    }


  • p>准备语句

      if($ vacancy-> save()){
    if($ vacancy-> ; is_active == 1){
    $ url = Yii :: app() - > createUrl('vacancies / view',array('id'=> $ model-> id));
    $ trainee_ids = Yii :: app() - > db-> createCommand() - > select('user_id') - > from('trainee') - > queryColumn();
    $ fu = Yii :: app() - > user-> id;
    $ msg =新的空缺已发布在< a href ='{$ url}'> {$ url}< / a> ;.
    $ ts = time();
    $ tt ='空缺通知:'.date('M j,Y');
    $ sql =INSERT INTO message(timestamp,from_user_id,title,message,to_user_id)VALUES(:ts,:fu,:tt,:msg,:tu);
    if($ trainee_ids!= null){
    foreach($ trainee_ids as $ trainee_id){

    $ command = Yii :: app() - > db-> createCommand($的SQL);
    $ command-> bindParam(:ts,$ ts,PDO :: PARAM_INT);
    $ command-> bindParam(:fu,$ fu,PDO :: PARAM_INT);
    $ command-> bindParam(:tt,$ tt,PDO :: PARAM_STR);
    $ command-> bindParam(:msg,$ msg,PDO :: PARAM_STR);
    $ command-> bindParam(:tu,$ trainee_id,PDO :: PARAM_INT);

    $ command-> execute();

    }
    }
    }
    }




研究



我还检查了以下网站(我只允许发布两个链接)他们要求操作等待请求完成或需要curl(我在部署服务器上无法访问)或需要外部库。我希望本地PHP实现。





编辑



通过以这种方式重写我的查询(将用户循环移到数据库层),我能够大大减少响应时间: p>

  public function actionCreate(){
$ user = YumUser :: model() - > findByPk(Yii :: app () - >用户> ID);
$ model = new职位空缺;
$ model-> corporate_id = $ user-> professional-> institution-> corporate-> id;
$ model-> date_posted = date('Y-m-d');
$ model-> last_modified = date('Y-m-d H:i:s');

if(isset($ _ POST ['Vacancies'])){
$ model-> setAttributes($ _ POST ['Vacancies']);
if($ model-> save()){
if($ model-> is_active == 1){
$ url = Yii :: app() - > createAbsoluteUrl ( '空位/视图',阵列( 'ID'=> $模型 - > ID));
$ fu = Yii :: app() - > user-> id;
$ msg =新的空缺已发布在< a href ='{$ url}'> {$ url}< / a> ;.
$ ts = time();
$ tt ='新空缺:'$ model-> title;
$ sql ='INSERT INTO message(timestamp,from_user_id,title,message,to_user_id)SELECT:ts,:fu,:tt,:msg,t.user_id FROM trainee t'
Yii :: app() - > db-> createCommand($ sql) - > execute(array(':ts'=> $ ts,':fu'=> $ fu, :TT '=> $ TT,':MSG'=> $ MSG));
}
if(Yii :: app() - > getRequest() - > getIsAjaxRequest())
Yii :: app() - > end();
else
$ this-> redirect(array('view','id'=> $ model-> id));
}
}
$ this-> render('create',array('model'=> $ model));
}

尽管如此,如果有人可以发布异步调用函数,这将是很好的

解决方案

通常,这些问题的解决方案是将消息总线集成到系统中。您可以考虑像 Beanstalkd 这样的产品。这需要在您的服务器上安装软件。
我想这个建议将被称为使用外部库。



如果您可以访问部署服务器,您可以添加cronjob(或mayb a sysadmin可以)你可以考虑一个cronjob,对一个从控制器方法填充的数据库中的作业队列读取作业的脚本进行php-cli调用。



如果您无法在正在运行的服务器上安装软件,您可以考虑使用SAAS解决方案,例如 Iron.io 为您主持总线功能。 Iron.io正在使用所谓的推送队列。使用推送队列,消息总线主动地对具有消息内容的注册听众进行请求(推送)。这可能会起作用,因为它不需要您执行卷曲请求。



如果上述都不可行;你的手被束缚另一个与此主题相关的帖子:可伸缩的PHP延迟处理


Question

I want to know if it is possible to asynchronously invoke a Yii controller method from one of its actions while the action renders a view, leaving the method to complete a long running operation. I would love to do something like the code below and I don't need to return a result from my_long_running_func.

public function actionCreate() {
    $model = new Vacancies;
    if (isset($_POST['Vacancies'])) {
        $model->setAttributes($_POST['Vacancies']);
        $model->save();
        //I wish :)
        call_user_func_async('my_long_running_func',$model);
    }
    $this->render('create', array( 'model' => $model));
}

Problem

I am trying to write a controller action in Yii that posts a vacancy and notifies interested subscribers of the post. The problem is that it takes a long time to execute the notification query.

Now I am searching for a way to asynchronously run the query so the poster sees his response in as little time as possible while the query runs in the background in a way similar to C# delegates or events.

The solutions I googled up performed asynchronous request(s) during the course of the controller action but all I want to do is to run a method of the controller asynchronously and the action had to wait till the request(s) were completed.

Attempted

I have tried the following methods but the query is still slow for my test data of about 1500 users.

  • Yii ActiveRecord

    if ($vacancy->save()) {                
        if($vacancy->is_active == 1) {
            $url = Yii::app()->createUrl('vacancies/view',array('id'=>$model->id));
            $trainees = YumUser::getUsersByRole('Trainees');
            if($trainees!=null) {
                foreach($trainees as $trainee){
                    $message = new YumMessage;
                    $message->from_user_id = Yii::app()->user->id;
                    $message->title = 'Vacancy Notification: '.date('M j, Y');
                    $message->message = "A new vacancy has been posted at <a href='{$url}'>{$url}</a>.";
                    $message->to_user_id = $trainee->id;
                    $message->save();                
                }
            }
        }    
    }
    

  • Yii Data Access Objects

    if ($vacancy->save()) {        
        if($vacancy->is_active == 1) {
            $url = Yii::app()->createAbsoluteUrl('vacancies/view',array('id'=>$model->id));
            $trainee_ids=Yii::app()->db->createCommand()->select('user_id')->from('trainee')->queryColumn();
            $fid=Yii::app()->user->id;
            $msg="A new vacancy has been posted at <a href='{$url}'>{$url}</a>.";
            $ts = time();
            $tt = 'Vacancy Notification: '.date('M j, Y');
            if($trainee_ids!=null) {
                foreach($trainee_ids as $trainee_id){
                    Yii::app()->db->createCommand()
                      ->insert('message',array('timestamp'=>$ts,'from_user_id'=>$fid,'to_user_id'=>$tid,'title'=>$tt,'message'=>$msg));
                }
            }
        }
    }
    

  • Prepared Statements

    if ($vacancy->save()) {                
        if($vacancy->is_active == 1) {
            $url = Yii::app()->createUrl('vacancies/view',array('id'=>$model->id));                    
            $trainee_ids=Yii::app()->db->createCommand()->select('user_id')->from('trainee')->queryColumn();
            $fu=Yii::app()->user->id;
            $msg="A new vacancy has been posted at <a href='{$url}'>{$url}</a>.";
            $ts = time();
            $tt = 'Vacancy Notification: '.date('M j, Y');
            $sql="INSERT INTO message (timestamp,from_user_id,title,message,to_user_id) VALUES (:ts,:fu,:tt,:msg,:tu)";
            if($trainee_ids!=null) {
                foreach($trainee_ids as $trainee_id){
    
                    $command=Yii::app()->db->createCommand($sql);
                    $command->bindParam(":ts",$ts,PDO::PARAM_INT);
                    $command->bindParam(":fu",$fu,PDO::PARAM_INT);
                    $command->bindParam(":tt",$tt,PDO::PARAM_STR);
                    $command->bindParam(":msg",$msg,PDO::PARAM_STR);
                    $command->bindParam(":tu",$trainee_id,PDO::PARAM_INT);
    
                    $command->execute();
    
                }
            }
        }
    }
    

Research

I have also checked the following websites (I'm only allowed to post two links) but they either require the action to wait for the request to be completed or need curl (which I don't have access to on the deployment server) or need an external library. I was hoping for a native PHP implementation.

Edit

I was able to decrease response time considerably by rewriting my query in this way (moving the user loop to the database layer):

public function actionCreate() {
    $user=YumUser::model()->findByPk(Yii::app()->user->id);
    $model = new Vacancies;
    $model->corporate_id=$user->professional->institution->corporate->id;
    $model->date_posted=date('Y-m-d');
    $model->last_modified=date('Y-m-d H:i:s');

    if (isset($_POST['Vacancies'])) {
        $model->setAttributes($_POST['Vacancies']);
        if ($model->save()) {                
            if($model->is_active == 1) {
                $url = Yii::app()->createAbsoluteUrl('vacancies/view',array('id'=>$model->id));                    
                $fu=Yii::app()->user->id;
                $msg="A new vacancy has been posted at <a href='{$url}'>{$url}</a>.";
                $ts = time();
                $tt = 'New Vacancy: '.$model->title;
                $sql='INSERT INTO message (timestamp,from_user_id,title,message,to_user_id) SELECT :ts,:fu,:tt,:msg,t.user_id FROM trainee t';
                Yii::app()->db->createCommand($sql)->execute(array(':ts'=>$ts,':fu'=>$fu,':tt'=>$tt,':msg'=>$msg));
            }                
            if (Yii::app()->getRequest()->getIsAjaxRequest())
                Yii::app()->end();
            else
                $this->redirect(array('view', 'id' => $model->id));
        }
    }
    $this->render('create', array( 'model' => $model));
}

Notwithstanding, it would be nice if someone could post a way to call functions asynchronously.

解决方案

Typically the solution for these kind of problems would be to integrate a message-bus in your system. You could consider a product like Beanstalkd. This requires installing software on your server. I suppose this suggestion would be called "using an external library".

If you can access the deployment server and you can add cronjob (or mayb a sysadmin can) you could consider a cronjob that does a php-cli call to a script that reads jobs from a job queue in your database which is filled by the controller method.

If you cannot install software on the server you're running you could consider using a SAAS solution like Iron.io to host the bus functionality for you. Iron.io is using what is called a push queue. With a push queue the message bus actively performs a request (push) to the registered listeners with the message content. This might work since it doesn't require you to do a curl request.

If none of the above is possible; your hands are tied. Another post which is quite relevant on the subject: Scalable, Delayed PHP Processing

这篇关于PHP异步方法调用Yii框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆