Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task is not executed as async. #15

Open
giwrgos88 opened this issue Oct 25, 2016 · 5 comments
Open

Task is not executed as async. #15

giwrgos88 opened this issue Oct 25, 2016 · 5 comments

Comments

@giwrgos88
Copy link

giwrgos88 commented Oct 25, 2016

Hello I'm using your package to implement async tasks.The basic idea is that I'm giving the option to the admin from the dashboard to create a post with some related videos. The videos are stored on the server but when he creates the post I want to move the videos that he selected to another platform and after the upload finish to save the response on a table with a foreign key of the post ID.
My problem is that instead of saving the post and then create an async task to upload the video on the platform it keeps wait for the video to be uploaded and then to refresh the page.

Here is my code

function init_async_task() {
    if (!class_exists('Upload_Videos_Async', false)) {
        new Upload_Videos_Async(WP_Async_Task::LOGGED_IN);
    }
}

add_action('plugins_loaded', 'init_async_task');
add_action('wp_async_save_post', 'move_videos_to_platform', 10, 2);
function move_videos_to_platform($id) {
//upload here the videos
}



class Upload_Videos_Async extends WP_Async_Task {

    protected $action = 'save_post';

    protected $argument_count = 1;

    public function __construct($auth_level = 0) {
        parent::__construct(parent::LOGGED_IN);
    }

    /**
     * Prepare data for the asynchronous request
     *
     * @throws Exception If for any reason the request should not happen
     *
     * @param array $data An array of data sent to the hook
     *
     * @return array
     */
    protected function prepare_data($data) {
        $returnData = ['post_id' => $data[0]];
        $files = [];
        $http = herbert('http');
        if ($http->has('file_name')) {

            foreach ($http->get('file_name') as $key => $value) {
                $tempKey = str_replace('.mp4', '', $value);
                $files[$tempKey] = $value;
            }
        }

        if (count($files) > 0) {
            $returnData['file_name'] = http_build_query($files);
        }
        return $returnData;
    }

    /**
     * Run the async task action
     */
    protected function run_action() {
        $http = herbert('http');
        $post = get_post($http->get('post_id'));
        if ($post) {
            if ($post->post_type == 'futures-video')
            // Assuming $this->action is 'save_post'
            {
                if ($http->has('file_name')) {
                    $files = [];
                    foreach (glob($_SERVER['DOCUMENT_ROOT'] . '/*.mp4') as $file) {
                        $tempKey = str_replace('.mp4', '', basename($file));
                        $tempKey = str_replace('.', '_', $tempKey);
                        $files[$tempKey] = $file;
                    }

                    $urlFiles = [];
                    parse_str($http->get('file_name'), $urlFiles);
                    $count = 0;
                    foreach ($urlFiles as $key => $filepath) {
                        $key = array_search(basename($filepath), $urlFiles);
                        if ($key !== false) {
                            $videos = new Videos;
                            $videos->name = $key;
                            $videos->post_id = $post->ID;
                            $videos->status = 'pending';
                            $videos->save();
                            $count++;
                        }
                    }
                    if ($count > 0) {
                        do_action("wp_async_$this->action", $post->ID, $post);
                    }
                }
            }
        }
    }

}

At the end if the videos didn't uploaded for any reason I want to execute the same tasks to re-upload them. How I can call the async task?
any help?

@ericmann
Copy link
Contributor

if (!class_exists('Upload_Videos_Async', false)) {
    new Upload_Videos_Async(WP_Async_Task::LOGGED_IN);
}

Before even looking at the rest of your code ... this chunk right here means you'll never have an Upload_Videos_Async object instantiated. The class_exists() function is meant to test if a class is defined, not if it's instantiated. If the class is defined in your code, the while conditional up there will evaluate to false and the object will never be created. If the class isn't defined, then it'll evaluate to true and you'll get an error when trying to instantiate a nonexistent class.

@giwrgos88
Copy link
Author

thank you @ericmann for your reply. Also tested it without having the class_exist function.

@ericmann
Copy link
Contributor

My problem is that instead of saving the post and then create an async task to upload the video on the platform it keeps wait for the video to be uploaded and then to refresh the page.

The videos will still need to upload to WordPress before WP can do anything with them. Are you saying the page is waiting to upload to a separate server as well, or just that it's waiting to upload to WordPress first?

Second, you've got a couple of things ... out of order perhaps with your code.

The ::run_action() method should only be kicking off the wp_async_$this->action event. The actual logic to upload the video should happen in the move_videos_to_platform() function bound to that event. I say this because that function should be built such that it can be tied to either the custom async action or a traditional synchronous action.

Either way, ::run_action() won't fire synchronously. It is fired in response to a non-blocking POST request from WordPress to itself. If you disable the function entirely, you can see the flow I'm talking about. Maybe edit the function to write to a log and return (rather than upload videos) to see when it's being triggered ...

@giwrgos88
Copy link
Author

giwrgos88 commented Oct 26, 2016

Hello @ericmann. As i said on my first post the videos already exist on the server where the wordpress is hosted. You can see it from my code as well.

foreach (glob($_SERVER['DOCUMENT_ROOT'] . '/*.mp4') as $file) {
...
}

Therefore I don't need to wait to upload the video on wordpress first and then move it to the other server.

So in the ::run_action() I'm only saving the videos that the user choose to upload it on the other server inside the database with pending status.


    /**
     * Run the async task action
     */
    protected function run_action() {
        $http = herbert('http');
        $post = get_post($http->get('post_id'));
        if ($post) {
            if ($post->post_type == 'futures-video')
            // Assuming $this->action is 'save_post'
            {
                if ($http->has('file_name')) {
                    $files = [];
                    foreach (glob($_SERVER['DOCUMENT_ROOT'] . '/*.mp4') as $file) {
                        $tempKey = str_replace('.mp4', '', basename($file));
                        $tempKey = str_replace('.', '_', $tempKey);
                        $files[$tempKey] = $file;
                    }

                    $urlFiles = [];
                    parse_str($http->get('file_name'), $urlFiles);
                    $count = 0;
                    foreach ($urlFiles as $key => $filepath) {
                        $key = array_search(basename($filepath), $urlFiles);
                        if ($key !== false) {
                            $videos = new Videos;
                            $videos->name = $key;
                            $videos->post_id = $post->ID;
                            $videos->status = 'pending';
                            $videos->save();
                            $count++;
                        }
                    }
                    if ($count > 0) {
                        do_action("wp_async_$this->action", $post->ID, $post);
                    }
                }
            }
        }
    }

Then inside the move_videos_to_platform I'm collecting all the entries which are pending and have post id the given id and the using guzzle I'm uploading the videos to the second server.

The problem is that the move_videos_to_platform function is not executed in a background process but when you click the save button it waits to upload the video on the second server and then refresh the page.

Do I need to make any configuration on the server in order to work the queuing?

@PiotrCzapla
Copy link

I have a similar issue, your asynctask is being used in PixerlYourSite. It makes the page that use this class looks like it is loading even though all the html is already sent to the customer. In new relic it looks like you run a synchronous request using curl to admin-post.php, and the main request is waiting for the sub request to finish.

This make some sense so that the subrequest isn't killed by the server when client drops the connection, but on the other hand it doesn't make much sense to run curl at all, as the async call could simply run in the same php process in the shutdown action and this would have the same effect. (if only one action is spawned at a time)

My guess is that @giwrgos88 is waiting for his main request to return, and this won't happen until the Async Task process finishes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants