代码之家  ›  专栏  ›  技术社区  ›  Simpledev

不允许“Closure”的Laravel队列序列化

  •  1
  • Simpledev  · 技术社区  · 6 年前

    我需要帮助用Laravel分派作业,似乎系统在使用队列作业时尝试序列化闭包,所以出现了这个错误。

    我如何解决这个问题?我也试过这个包裹
    https://github.com/jeremeamia/super_closure
    但这对我来说不起作用。

    这是我的代码:

    public function getPosts(\SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) //get all post of logged user
    {
        dispatch(new SyncFacebook($fb));
    }
    

    以及要分派的作业:

    <?php
    
    namespace App\Jobs;
    
    use Illuminate\Bus\Queueable;
    use Illuminate\Queue\SerializesModels;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    
    use Session, DB, Carbon\Carbon, Auth;
    
    use App\{
        User, Reaction, Post, Synchronisation
    };
    
    class SyncFacebook implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
        protected $fb;
    
        public function __construct($fb)
        {
            $this->fb = $fb;
        }
    
        public function handle()
        {
            set_time_limit(0);
            $user = Auth::user();
    
            try {
              $response = $this->fb->get('/me/posts?limit=100', session('fb_user_access_token'));
            } catch(\Facebook\Exceptions\FacebookSDKException $e) {
              dd($e->getMessage());
            }
    
            $postEdge = $response->getGraphEdge();
    
            if(count($postEdge) > 0){
    
                $pageCount = 0;
                $maxPages = 9000000000000000000;
    
                DB::beginTransaction();
    
                try{
    
                    do{
                        foreach ($postEdge as $result) {
                            $result = $result->asArray();
                            $post_id = $result['id'];
    
                            $post = Post::where('post_id', $post_id)->first() ?: new Post;
                            $post->post_id = $post_id;
                            $post->user_id = $user->id;
                            $post->timezone = collect($result['created_time'])->toArray()['timezone'];
                            $post->post_date = collect($result['created_time'])->toArray()['date'];
                            $post->content = $result['message'] ?? $result['story'] ?? '';
                            $post->save();
    
                            $req = !empty(Synchronisation::whereUserId($user->id)->orderBy('id','desc')->date) ? 
                            $post_id.'/reactions?limit=100&summary=total_count&since'.time(Synchronisation::whereUserId($user->id)->orderBy('id','desc')->date) : 
                            $post_id.'/reactions?limit=100&summary=total_count';
    
                            try {
                              $response = $this->fb->get($req, session('fb_user_access_token'));
                            } catch(\Facebook\Exceptions\FacebookSDKException $e) {
                              dd($e->getMessage());
                            }
                            $reactionEdge = $response->getGraphEdge();
    
                            $total_reactions = $reactionEdge->getMetaData()['summary']['total_count'] ?? null;
                            //dd($total_reactions);
                            $post->total_reactions = $total_reactions;
                            $post->save();
    
                            if(count($reactionEdge)){
                                $pagesReactionCount = 0;
                                do{
                                    foreach($reactionEdge as $react){
                                        $react = $react->asArray();
    
                                        $reaction = Reaction::where('reaction_id', $react['id'])->first() ?: new Reaction;
                                        $reaction->type = $react['type'];
                                        $reaction->reaction_id = $react['id'];
                                        $reaction->post_id = $post->id;
                                        $reaction->author = $react['name'];
                                        $reaction->save();
                                    }
                                    $pagesReactionCount++;
                                }
    
                                while($pagesReactionCount < $maxPages && $reactionEdge = $this->fb->next($reactionEdge));
    
    
                            }
                        }
                        $pageCount++;
                      }
                      while ($pageCount < $maxPages && $postEdge = $this->fb->next($postEdge));
    
                      $synchro = new Synchronisation;
                      $synchro->user_id = $user->id;
                      $synchro->date = now();
                      $synchro->completed = true;
                      $synchro->save();
                }
                catch(ValidationException $e){
                    DB::rollback();
                    if(env('APP_ENV') != 'production'){
                        dd($e->getMessage());
                    }
                }
    
                DB::commit();
            }
            else{
                //no post
            }
        }
    }
    

    $this->fb = $fb; //不允许序列化“Closure”

    2 回复  |  直到 6 年前
        1
  •  5
  •   lufc    6 年前

    我的理解是,不能在作业中包含不可序列化的变量,因为Laravel在存储作业详细信息时不知道如何处理它们。

    因此,您需要删除 $fb construct() 方法和相关 protected $fb; $this->fb = $fb; 线

    相反,你有两个选择

    1) 简单

    创建新的 \SammyK\LaravelFacebookSdk\LaravelFacebookSdk 对象 handle() 方法,例如。

    public function handle() {
        $fb = new \SammyK\LaravelFacebookSdk\LaravelFacebookSdk;
    
        '.... replace all $this->fb with $fb
    }
    

    2) 高级

    如果需要传递之前使用的特定FB实例,请注册 FacebookSDK Service Provider inject it into the handler 如文件所示。

    例如。

    public function handle(FacebookSDK $fb) {
    
        '.... replace all $this->fb with $fb
    
    }
    

    当您为Facebook SDK注册绑定服务容器时,此类型在 句柄() 方法自动检索$fb实例并将其注入方法中以供使用。您可以决定是每次创建一个新的FacebookSDK对象,还是只创建一个并始终使用该对象(称为单例)。

        2
  •  0
  •   Thomas    5 年前

    有时,将队列从同步更改为数据库也可以解决此问题。