Opened 6 years ago
Closed 5 years ago
#44886 closed defect (bug) (wontfix)
Race condition in REST API, can cause data loss
Reported by: | rldk | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | normal | Version: | 4.9.8 |
Component: | Posts, Post Types | Keywords: | |
Focuses: | rest-api | Cc: |
Description
If, while a client is downloading a collection from the REST API, a
second client does something that should remove from that collection
a record which the first client has already downloaded, the REST API
will remove some *other* record from the first client’s collection in
order to make the total number of downloaded records be accurate.
For the demonstration below, the race condition is made repeatable by
having both clients pause at exactly the right (i.e. wrong!) moment.
Summary of the demonstration:
- The site holds “Important Post 1” through “Important Post 12”.
- Someone accidentally publishes “My test post”.
- An automated client begins downloading all posts (e.g. for backup, or syndication).
- Someone deletes “My test post”.
- The automated client finishes downloading.
- Later, when someone needs the downloaded dataset, “Important Post 3” is
missing, just because someone deleted “My test post” during the download.
This bug was reported downstream at https://bugs.debian.org/898309.
To demonstrate:
(Files attached to this report are prefixed with “~/Downloads/” below.)
Installing and configuring the server software:
This isn’t meant to be secure; don’t expose it on a public IP address!
# cat /etc/issue.net Debian GNU/Linux 9 # mkdir ~/wprestrace-server # cd ~/wprestrace-server # cp -a ~/Downloads/basic-auth.tar.gz . # wget https://wordpress.org/wordpress-4.9.8.tar.gz [...] # wget https://www.apachefriends.org/xampp-files/7.2.9/xampp-linux-x64-7.2.9-0-installer.run [...] # chmod +x xampp-linux-x64-7.2.9-0-installer.run # ./xampp-linux-x64-7.2.9-0-installer.run
(accept defaults, install, launch)
Manage Servers > MySQL Database > Start
# cd /opt/lampp/htdocs # tar xpzf ~/wprestrace-server/wordpress-4.9.8.tar.gz # mv wordpress wp # tar xpzf ~/wprestrace-server/basic-auth.tar.gz -C wp/wp-content/plugins # chown -R daemon:daemon wp #
browse to http://localhost/phpmyadmin/
Databases
Database name: root_wp
Collation: utf8_unicode_ci
Create
browse to http://localhost/wp/
Continue
Let’s go!
Database Name: root_wp
Username: root
Password:
Submit
Run the installation
Site Title: tempsite
Username: username
Password: password
Install WordPress
Log In
Plugins > Installed Plugins > JSON Basic Authentication > Activate
Done installing and configuring the server software.
Installing and configuring the client software:
# mkdir ~/wprestrace-client # cd ~/wprestrace-client # cp -a ~/Downloads/WpRestRacePopulate.js . # cp -a ~/Downloads/WpRestRaceDownloadAll.js . # cp -a ~/Downloads/WpRestRaceTestPost.js . # wget https://deb.nodesource.com/setup_8.x [...] # chmod +x setup_8.x # ./setup_8.x [...] # apt-get install nodejs [...] # node -v v8.11.4 # npm install -g wpapi + wpapi@1.1.2 added 33 packages in 2.636s #
Done installing and configuring the client software.
Reproducing the race condition:
# cd ~/wprestrace-client # export NODE_PATH=$(npm root -g) # # node WpRestRacePopulate.js username password http://localhost/wp/wp-json Created "Important Post 1". Created "Important Post 2". Created "Important Post 3". Created "Important Post 4". Created "Important Post 5". Created "Important Post 6". Created "Important Post 7". Created "Important Post 8". Created "Important Post 9". Created "Important Post 10". Created "Important Post 11". Created "Important Post 12". #
Open another terminal emulator.
When asked to press Enter below, don’t do it yet!
# cd ~/wprestrace-client # export NODE_PATH=$(npm root -g) # # node WpRestRaceTestPost.js username password http://localhost/wp/wp-json Created "My test post". Press Enter to delete it.
Go back to the original terminal emulator.
When asked to press Enter below, don’t do it yet!
# node WpRestRaceDownloadAll.js username password http://localhost/wp/wp-json Downloading all posts: Downloaded "My test post". Downloaded "Important Post 12". Downloaded "Important Post 11". Downloaded "Important Post 10". Downloaded "Important Post 9". Downloaded "Important Post 8". Downloaded "Important Post 7". Downloaded "Important Post 6". Downloaded "Important Post 5". Downloaded "Important Post 4". Press Enter to continue.
Go back to the second terminal emulator, and press Enter.
The command and output (including what you already saw) are:
# node WpRestRaceTestPost.js username password http://localhost/wp/wp-json Created "My test post". Press Enter to delete it. Deleted "My test post". #
Go back to the original terminal emulator, and press Enter.
The command and output (including what you already saw) are:
# node WpRestRaceDownloadAll.js username password http://localhost/wp/wp-json Downloading all posts: Downloaded "My test post". Downloaded "Important Post 12". Downloaded "Important Post 11". Downloaded "Important Post 10". Downloaded "Important Post 9". Downloaded "Important Post 8". Downloaded "Important Post 7". Downloaded "Important Post 6". Downloaded "Important Post 5". Downloaded "Important Post 4". Press Enter to continue. Downloaded "Important Post 2". Downloaded "Important Post 1". Downloaded "Hello world!". Finished downloading all posts: My test post Important Post 12 Important Post 11 Important Post 10 Important Post 9 Important Post 8 Important Post 7 Important Post 6 Important Post 5 Important Post 4 Important Post 2 Important Post 1 Hello world! End of listing. #
The DownloadAll client thinks that it successfully downloaded all posts,
but it never received “Important Post 3”!
Attachments (4)
Change History (8)
This ticket was mentioned in Slack in #core-restapi by timothybjacobs. View the logs.
5 years ago
#4
@
5 years ago
- Component changed from REST API to Posts, Post Types
- Milestone Awaiting Review deleted
- Resolution set to wontfix
- Status changed from new to closed
This was discussed in the REST API weekly meeting today, and we've established that this behavior isn't limited to the API; it may be observed if using normal archive views within a traditional WordPress site as well.
The converse of the issue is that you might see a post on two subsequent archive pages if additional content is published after you load the first page, but before the second:
- View page one, with posts 12 through 3
- New post is published
- Click "next page" and see posts 3 through 1
Because this is not specific to the REST API and appears to instead be a systemic issue with WordPress as a whole (hence the re-categorization as Posts/Post-Types), I'm going to close the ticket. In doing so I acknowledge that it's possible for this behavior to cause problems, but I don't see a path forward towards fixing it without fundamental architectural changes.
Related, possible duplicate of #44568