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

Expensive Function

Discussion in 'XenForo Development Discussions' started by silence, Aug 3, 2013.

  1. silence

    silence Well-Known Member

    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?
     
  2. Jeremy

    Jeremy XenForo Moderator Staff Member

    Can the function be optimized? What is your code?
     
  3. silence

    silence Well-Known Member

    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.
     
  4. Jeremy

    Jeremy XenForo Moderator Staff Member

    Does the user need the response from the TeamSpeak server?
     
  5. silence

    silence Well-Known Member

    No all it does it when the user triggers something that would create an alert, it sends an alert to the recipient on the server. The client triggering it doesn't need any response :)
     
  6. Jeremy

    Jeremy XenForo Moderator Staff Member

    silence likes this.
  7. silence

    silence Well-Known Member

  8. silence

    silence Well-Known Member

    Alright one more question, would executing it via exec() be a bad idea?
    And I can't exactly use sockets or fopen or curl to connect to it since I'm using an API to do all of this for me.
     
  9. Jeremy

    Jeremy XenForo Moderator Staff Member

    What API are you using?
     
  10. Chris D

    Chris D XenForo Developer Staff Member

    Also check out XenForo's deferred system.

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

    silence Well-Known Member

    Hohoho that sounds great :D
    XF needs documentation for devs :C
     
  12. silence

    silence Well-Known Member

    Hmm but srs, is there any documentation on it? I rather not go code hunting :/
     
  13. Jeremy

    Jeremy XenForo Moderator Staff Member

    There is currently no documentation on the deferred system that I have seen.
     
  14. Chris D

    Chris D XenForo Developer Staff Member

    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.
     
  15. silence

    silence Well-Known Member

    Ohhh I was confused on how exactly it knows what you want to run in the background :p
    Thanks for clearing that up!
     
  16. silence

    silence Well-Known Member

    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.
     
  17. Chris D

    Chris D XenForo Developer Staff Member

    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.
     
  18. JulianD

    JulianD Well-Known Member

    I need to save this post for future reference. Great work Chris. Thank you.
     
    Chris D likes this.
  19. silence

    silence Well-Known Member

    I'm getting zero errors :C that's why I'm so confused.
     
  20. Mike

    Mike XenForo Developer Staff Member

    You should try instantiating and running your deferred handler directly if you're having problems. You'll likely quickly notice that you'll be getting fatal errors as getModelFromCache() doesn't exist in it.
     

Share This Page