XF 2.0 Efficient method to call external API and update user table

BoostN

Well-known member
I'm calling an external API and then doing a check against the email passed and based on the result, I'm updating a field on the XF user record. Now, I want to be efficent with this.

I have two use cases:

1) The initial install where I need to sync this list to the current user table in XF.
2) Run the job once per night to keep values true from the Source (External API) to the XF user table.

PHP:
class Sync extends AbstractJob
{
    public function run($maxRunTime)
    {
        $startTime = microtime(true);

        $users = \XF::app()->finder('XF:User')->fetch();

        foreach ($users as $user) {
            $this->updateUser($user);

            if (microtime(true) - $startTime >= $maxRunTime) {
                return $this->resume();
            }

        }

        return $this->complete();
    }

    public function updateUser(\XF\Entity\User $user)
    {
        $app = \XF::app();

        /** @var \MyService\..\.. $myService */
        $myService = \XF::service('///MY SERVICE');
        $result = $myService->getStatus($user->email);
        $userOptions = $user->getRelationOrDefault('Option');

        if ($result == 'Something') {
            $userOptions->fastUpdate('my_option', true);
        }
        else
        {
            //DO SOMETHING ELSE
        }

    }

    public function getStatusMessage()
    {
        //////TODO
    }

    public function canCancel()
    {
        return true;
    }

    public function canTriggerByChoice()
    {
        return true;
    }

}

Any improvements or suggestions I can make from what I have? My service actually works well, just wanted to be sure I'm approaching this in the correct "XF2" way..
 
Any comments or suggestions ? Is the cron job my best method to mass update the user table from a 3rd party API?
 
I'm using this finder method to pull all users and then update each user profile with this loop below. You can see the full statement in the "spoiler code" in my first post.
PHP:
$users = \XF::app()->finder('XF:User')->fetch();
        
        foreach ($users as $user) {
            $this->updateUser($user);

            if (microtime(true) - $startTime >= $maxRunTime) {
                return $this->resume();
            }
        }
return $this->complete();

In my 'updateUser' function, I'm seeing the same "user" being logged multiple times. Is my finder or for loop incorrect? Why would I get the same usernames from my finder? I was assuming it would loop through each item in the array, correct?
 
Because you're breaking the loop and restarting, you're just processing the same users over and over. It's worth looking at how we do this sort of approach. You need to process users in order (explicitly) and then start processing from the next location.

You probably don't want to fetch all users like that. Depending on site size, this may require an enormous amount of data. You likely want to at least be limiting to a known maximum amount. You need to be careful with this though, as just because you finished the foreach, doesn't mean that you're actually finished (you need to know that you got to the end because there are no other users to process).
 
Because you're breaking the loop and restarting, you're just processing the same users over and over. It's worth looking at how we do this sort of approach. You need to process users in order (explicitly) and then start processing from the next location.

You probably don't want to fetch all users like that. Depending on site size, this may require an enormous amount of data. You likely want to at least be limiting to a known maximum amount. You need to be careful with this though, as just because you finished the foreach, doesn't mean that you're actually finished (you need to know that you got to the end because there are no other users to process).

Thanks Mike. Any particular file I can look at to help me understand?
 
It's partially abstracted, but XF\Job\User follows that concept. If this is actually done via a job, you might actually be able to use the AbstractRebuildJob base to help.
 
Top Bottom