WPCloudDeploy uses a PHP ssh library to connect to WordPress servers in order to execute commands and collect information.
There are three execution models we use to manage this.
Direct execution is used for commands that we reasonably believe will take a short amount of time to execute. Most commands fall under this umbrella. These include:
Within the plugin code you will see this handled as follows:
$result = $this->execute_ssh( 'generic', $instance, array( 'commands' => $run_cmd ) );
Basically we submit a command to the server and wait the result. We then evaluate the result and do some stuff.
This is pretty straightforward. Unfortunately, if you want to give feedback to users when the command has a lot of output or is taking a long time to run, you can’t do this. If you try, the user will either think the command is not working/is frozen OR the command will time out and the user will see an error.
Thus, for long running commands, we need a more complex process in which we can offer feedback to the user and prevent timeouts.
Before going into the two different types of long-running commands we implement, lets get some terminology down:
There are two servers involved:
So, we need to name these two servers so that its clear which server we are talking about at any one time.
This model is used in things like DEPLOYING A NEW SERVER and INSTALLING A NEW WordPress SITE. It works using a set of timers and cron processes and goes something like this:
So how does this whole cycle end?
It ends when the Target WordPress server that we are talking to sends us back a notification via a REST API call. When we receive this call, we mark the command as completed. The next time the JS UI timer asks for logs, the WPCloudDeploy Plugin server then responds with the logs as well as an indication that the command is completed. Upon receipt of the “command done” indicator, the browser can then turn off its timer to stop polling the WPCloud Deploy Plugin server for logs.
This model is used in things like BACKUP and RESTORE. It closely resembles the TYPE 1 model and, just like it, works using a set of timers and cron processes and goes something like this:
So how does this whole cycle end?
It ends when the Target WordPress server that we are talking to sends us back a notification via a REST API call. When we receive this call, we mark the command as completed. The next time the UI timer asks for logs, the WPCloudDeploy Plugin server then responds with the logs as well as an indication that the command is completed. The browser can then turn off its timer.
So, you must be asking yourself, how does the Target WordPress server know which REST API endpoint to use and when to call it?
Good Question!
95% of the time, when we submit a command to a Target WordPress server, its not just one command. Its a series of chained commands. They might look something like this:
sudo -i -E cd /root && sudo -E \rm -f 03-disable-remove-site.sh && sudo -E wget --no-check-certificate -O 03-disable-remove-site.sh https://wpclouddeploypluginserver.com/wp-content/plugins/wp-cloud-deploy/includes/core/apps/wordpress-app/scripts/v1/raw/03-disable-remove-site.txt && export action=remove domain=cf108.wpvix.com && sudo -E dos2unix 03-disable-remove-site.sh && sudo -E bash 03-disable-remove-site.sh
For long running commands, we include a sub-command to call the rest api endpoint as the very last command in the chain – see the BOLD line in the code sample below:
echo "done" && { sudo -i -E cd /root && sudo -E apt-get update -yqm >> wordpress-app_prepare_server.log.intermed 2>&1 && sudo -E apt-get install -yqm dos2unix sendmail >> wordpress-app_prepare_server.log.intermed 2>&1 && sudo -E apt-get install -y vnstat >> wordpress-app_prepare_server.log.intermed 2>&1 && sudo -E wget --no-check-certificate -O 01-prepare_server.sh https://wpclouddeploypluginserver.com/wp-content/plugins/wp-cloud-deploy/includes/core/apps/wordpress-app/scripts/v1/raw/01-prepare_server.txt && export interactive=no && sudo -E dos2unix 01-prepare_server.sh && sudo -E bash 01-prepare_server.sh >> wordpress-app_prepare_server.log.intermed 2>&1 && sudo -E mv wordpress-app_prepare_server.log.intermed wordpress-app_prepare_server.log.done && sudo -E wget -q https://wpclouddeploypluginserver.com/wp-json/wordpress-app/v1/command/82482/prepare_server/completed/1586126728/; } > /dev/null 2>&1 &