pixelfed/pixelfed

View on GitHub
app/Jobs/FollowPipeline/FollowServiceWarmCache.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php

namespace App\Jobs\FollowPipeline;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use App\Services\AccountService;
use App\Services\FollowerService;
use Cache;
use DB;
use Storage;
use App\Follower;
use App\Profile;

class FollowServiceWarmCache implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $profileId;
    public $tries = 5;
    public $timeout = 5000;
    public $failOnTimeout = false;

    /**
     * Get the middleware the job should pass through.
     *
     * @return array<int, object>
     */
    public function middleware(): array
    {
        return [(new WithoutOverlapping($this->profileId))->dontRelease()];
    }

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($profileId)
    {
        $this->profileId = $profileId;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $id = $this->profileId;

        if(Cache::has(FollowerService::FOLLOWERS_SYNC_KEY . $id) && Cache::has(FollowerService::FOLLOWING_SYNC_KEY . $id)) {
            return;
        }

        $account = AccountService::get($id, true);

        if(!$account) {
            Cache::put(FollowerService::FOLLOWERS_SYNC_KEY . $id, 1, 604800);
            Cache::put(FollowerService::FOLLOWING_SYNC_KEY . $id, 1, 604800);
            return;
        }

        $hasFollowerPostProcessing = false;
        $hasFollowingPostProcessing = false;

        if(Follower::whereProfileId($id)->orWhere('following_id', $id)->count()) {
            $following = [];
            $followers = [];
            foreach(Follower::where('following_id', $id)->orWhere('profile_id', $id)->lazyById(500) as $follow) {
                if($follow->following_id != $id && $follow->profile_id != $id) {
                    continue;
                }
                if($follow->profile_id == $id) {
                    $following[] = $follow->following_id;
                } else {
                    $followers[] = $follow->profile_id;
                }
            }

            if(count($followers) > 100) {
                // store follower ids and process in another job
                Storage::put('follow-warm-cache/' . $id . '/followers.json', json_encode($followers));
                $hasFollowerPostProcessing = true;
            } else {
                foreach($followers as $follower) {
                    FollowerService::add($follower, $id);
                }
            }

            if(count($following) > 100) {
                // store following ids and process in another job
                Storage::put('follow-warm-cache/' . $id . '/following.json', json_encode($following));
                $hasFollowingPostProcessing = true;
            } else {
                foreach($following as $following) {
                    FollowerService::add($id, $following);
                }
            }
        }

        Cache::put(FollowerService::FOLLOWERS_SYNC_KEY . $id, 1, 604800);
        Cache::put(FollowerService::FOLLOWING_SYNC_KEY . $id, 1, 604800);

        $profile = Profile::find($id);
        if($profile) {
            $profile->following_count = DB::table('followers')->whereProfileId($id)->count();
            $profile->followers_count = DB::table('followers')->whereFollowingId($id)->count();
            $profile->save();
        }

        AccountService::del($id);

        if($hasFollowingPostProcessing) {
            FollowServiceWarmCacheLargeIngestPipeline::dispatch($id, 'following')->onQueue('follow');
        }

        if($hasFollowerPostProcessing) {
            FollowServiceWarmCacheLargeIngestPipeline::dispatch($id, 'followers')->onQueue('follow');
        }

        return;
    }
}