• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

Expensive Function

silence

Well-known member
#1
Basically, I want to call a function everytime an alert is made (hooking datawriter) and the function takes around 900ms each call. Would there be a way to push that function to the background so the client doesn't have to wait 5 years for it to finish?
 

silence

Well-known member
#3
Can the function be optimized? What is your code?
Not exactly. It's querying a Teamspeak server so since the connection differs for each person using the addon, it would be nice to run the function in the background so the client doesn't have to wait.
 

Chris D

XenForo developer
Staff member
#10
Also check out XenForo's deferred system.

Perfect for those processes that take longer than desired. It will run entirely in the background.
 

Chris D

XenForo developer
Staff member
#14
I didn't need any documentation to work out what was going on...

Start with a blank PHP file:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
Normally there'd be a bit more logic before returning false. The reason for that is, Deferred classes usually run for longer periods of time that the 900ms you mention and they're usually working with much larger amounts of data.

You normally work with the data in batches and if you still have data to process you return $data at the end, which will signal the Deferred system to enter another Deferred entry and work with the next batch of data and so on.

The "bit more logic" I mentioned would usually check if there's any more data to work with. If there is, return $data. If there isn't, return false.

So, in your case, just returning false at the end is absolutely fine.

More on the actual deferred class in a minute. To execute your Deferred action:

PHP:
XenForo_Application::defer('YourAddOn_Deferred_SomeAction', $data);
$data should simply contain an array of data you need to work with.

Back to your Deferred class:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
The data you passed in is available in $data. You now just need to write your function that does things with that data. It will run entirely in the background and should be invisible to the end user.
 

silence

Well-known member
#15
I didn't need any documentation to work out what was going on...

Start with a blank PHP file:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
Normally there'd be a bit more logic before returning false. The reason for that is, Deferred classes usually run for longer periods of time that the 900ms you mention and they're usually working with much larger amounts of data.

You normally work with the data in batches and if you still have data to process you return $data at the end, which will signal the Deferred system to enter another Deferred entry and work with the next batch of data and so on.

The "bit more logic" I mentioned would usually check if there's any more data to work with. If there is, return $data. If there isn't, return false.

So, in your case, just returning false at the end is absolutely fine.

More on the actual deferred class in a minute. To execute your Deferred action:

PHP:
XenForo_Application::defer('YourAddOn_Deferred_SomeAction', $data);
$data should simply contain an array of data you need to work with.

Back to your Deferred class:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
The data you passed in is available in $data. You now just need to write your function that does things with that data. It will run entirely in the background and should be invisible to the end user.
Ohhh I was confused on how exactly it knows what you want to run in the background :p
Thanks for clearing that up!
 

silence

Well-known member
#16
I didn't need any documentation to work out what was going on...

Start with a blank PHP file:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
Normally there'd be a bit more logic before returning false. The reason for that is, Deferred classes usually run for longer periods of time that the 900ms you mention and they're usually working with much larger amounts of data.

You normally work with the data in batches and if you still have data to process you return $data at the end, which will signal the Deferred system to enter another Deferred entry and work with the next batch of data and so on.

The "bit more logic" I mentioned would usually check if there's any more data to work with. If there is, return $data. If there isn't, return false.

So, in your case, just returning false at the end is absolutely fine.

More on the actual deferred class in a minute. To execute your Deferred action:

PHP:
XenForo_Application::defer('YourAddOn_Deferred_SomeAction', $data);
$data should simply contain an array of data you need to work with.

Back to your Deferred class:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
The data you passed in is available in $data. You now just need to write your function that does things with that data. It will run entirely in the background and should be invisible to the end user.
Yeah I can't get a response out if it :C
Here is where I'm calling it:
PHP:
    protected function _postSave()
    {
        $parent = parent::_postSave();

        $data = array('user_id' => $this->get('user_id'), 'alert_id' => $this->get('alert_id'));

        XenForo_Application::defer('Teamspeak_Deferred_Alert', $data);

        return $parent;
    }
And the deferred:
PHP:
<?php

class Teamspeak_Deferred_Alert extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        $teamspeak = new Teamspeak_Helper_Alert();
        $alert = getAlertById($data['alert_id']);
        $alert = $this->_getAlertModel()->_getContentForAlerts($alert, $data['user_id']);

        $auth_id = $this->_getAccountModel()->getAuthID('1');
        $teamspeak->_sendAlert('test', $auth_id);

        return false;
    }

    protected function _getAlertModel()
    {
        return $this->getModelFromCache('XenForo_Model_Alert');
    }

    protected function _getAccountModel()
    {
        return $this->getModelFromCache('Teamspeak_Model_Account');
    }

    protected function _getQueryHelper()
    {
        return $this->getModelFromCache('Teamspeak_Helper_Query');
    }
}
The function I'm calling works when in the datawriter but I'm dumbfounded as to why I can't get a response out of the deferred.
 

Chris D

XenForo developer
Staff member
#17
You might be getting a response, you just won't see it.

Clear your server error log in the admin cp.

Then trigger it again.

Then check the server error log. See if its logging anything.
 

JulianD

Well-known member
#18
I didn't need any documentation to work out what was going on...

Start with a blank PHP file:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
Normally there'd be a bit more logic before returning false. The reason for that is, Deferred classes usually run for longer periods of time that the 900ms you mention and they're usually working with much larger amounts of data.

You normally work with the data in batches and if you still have data to process you return $data at the end, which will signal the Deferred system to enter another Deferred entry and work with the next batch of data and so on.

The "bit more logic" I mentioned would usually check if there's any more data to work with. If there is, return $data. If there isn't, return false.

So, in your case, just returning false at the end is absolutely fine.

More on the actual deferred class in a minute. To execute your Deferred action:

PHP:
XenForo_Application::defer('YourAddOn_Deferred_SomeAction', $data);
$data should simply contain an array of data you need to work with.

Back to your Deferred class:

PHP:
<?php

class YourAddOn_Deferred_SomeAction extends XenForo_Deferred_Abstract
{
    public function execute(array $deferred, array $data, $targetRunTime, &$status)
    {
        // The code you want to execute here.
        return false;
   }
}
The data you passed in is available in $data. You now just need to write your function that does things with that data. It will run entirely in the background and should be invisible to the end user.
I need to save this post for future reference. Great work Chris. Thank you.