WordPress.org

Make WordPress Core

Opened 7 years ago

Closed 5 years ago

#4566 closed defect (bug) (worksforme)

Cron Not Getting Called (fsockopen failing)

Reported by: chewblocka Owned by: Nazgul
Milestone: 2.8 Priority: normal
Severity: normal Version: 2.2.1
Component: Administration Keywords: reporter-feedback
Focuses: Cc:

Description

This is similar to ticket #3565 and #3742, however slightly different. The first ticket was solved as a DNS issue, though that is not the case here. The second...the fsockopen is actually working and the user is seeing other errors. In this case, the wp-cron.php is never getting called (no entries in the apache access or error logs). The DNS resolution works like a charm. What is happening though is the fsockopen call in cron.php is failing with a connection refused error. The reason for this is that the firewall on the box is denying any request coming over the external interface claiming to originate from the current host. This is a fairly common firewall rule to deny spoofed IP packets. However, currently when cron.php attempts to do an fsockopen using the site_url, this is exactly what it is doing.

I propose the following solution:

Change cron.php to use the loopback interface in all instances (which is how I have solved the issue for my installation). This would involve doing the following:

  • Still get the site_url variable to obtain the scheme and path
  • Replace $partshost? in the fsockopen command with localhost

This should be the default functionality, though may be beneficial to have a selection somewhere that will use the current functionality if desired/required.

Attachments (2)

4566.diff (957 bytes) - added by Nazgul 7 years ago.
cronloopback.php (309 bytes) - added by Nazgul 7 years ago.
Sample plugin

Download all attachments as: .zip

Change History (16)

comment:1 foolswisdom7 years ago

  • Milestone set to 2.3 (trunk)

comment:2 Nazgul7 years ago

I agree this should be pluggable, but it should not be the default.

It's a very common scenario to host multiple sites/domains on one machine. If you use the local loopback, which of those sites would that be? And what about the others?

Nazgul7 years ago

Nazgul7 years ago

Sample plugin

comment:3 Nazgul7 years ago

  • Keywords has-patch added
  • Owner changed from anonymous to Nazgul
  • Priority changed from high to normal
  • Severity changed from major to normal
  • Status changed from new to assigned

I've created a patch which introduces a new filter for manipulating the cron host.

I've also created a sample plugin which changes it to localhost, to getthe desired behaviour as mentioned by the reporter.

comment:4 follow-up: matt7 years ago

Calling localhost should be fine if you include the proper host: header.

comment:5 in reply to: ↑ 4 westi7 years ago

Replying to matt:

Calling localhost should be fine if you include the proper host: header.

Only if the apache or other httpd is listening on all interfaces which may not always be true on a multi-ip hosted server.

comment:6 Otto427 years ago

The reason for this fsockopen is to make the wp-cron.php file execute asynchronously, correct? There's other ways to do that, perhaps the program should try some of those other ways as well if one fails.

You could use pcntl_fork to do it, if the PHP process is not running as an Apache module. Fortunately, pcntl_fork gives you feedback when it won't work (return value of -1).

Alternately, if nothing else works, you could just include the wp-cron.php file and make it run that way. Yes, it won't be asynchronous, but at least it'll work.

comment:7 error7 years ago

I'm having exactly the same problem, for a different reason: my web server only serves the "localhost" virtual host on the loopback interface, and my hostname was defined in /etc/hosts as follows:
::1 www.homelandstupidity.us
Removing this definition seems to have fixed the problem.

comment:8 Nazgul7 years ago

  • Milestone changed from 2.3 to 2.4

comment:9 darkdragon7 years ago

There isn't really another method for reliably calling the wp-cron.php without blocking execution. What I mean is that there isn't one for works both on PHP4 and PHP5. Well, besides cURL, but you count on it to be installed and enabled on all shared hosts.

PHP5 does add several better ways, file_put_contents() along with streams to put the headers and nonblocking mode, would be a better method, but wouldn't solve the issue.

As far as my research as bought up, there is no real nonblocking PHP execution, unless you use multitasking method. The only problem with the multitasking PHP methods, is that they are also unreliable.

However, this doesn't correctly solve or have anything to do with the real problem.

[b]Suggestionb

Don't use '@', just disable warnings. If fsockopen fails, you should do some other checks, however, some troubleshooters might want to get the warnings and you hinder those attempts.

comment:10 intoxination7 years ago

I think this is a bigger problem then we actually realize. I have had 2 people ask me why their crons aren't firing and both of them turned out to be hosting issues. They have been upgrading constantly, so they have had cron since in came out in 2.1 in January. They just never noticed it before because they don't do future posting. In both cases it was plugins they added that use cron and they noticed it wasn't working. Since more plugins are starting to use cron, I think it's time to come up with a reasonable solution to the problem.

What I ended up doing for these two was create a simple plugin to remove to wp_cron hook. Then i had them modify wp_cron to get rid of the "check" and add wp-cron.php to a crontab in CPanel.

This might be something to consider doing in the core, especially since there are so many different ways that cron can break by hosting rules. It could even utilize the new update alerts in admin. Basically if a cron doesn't fire it sets a no_cron option (or something like that). During the update checks, this option is checked. If it exists then the admins are notified in the update box (or even via email) about the problem. With a link to a codex page on using crontab. Of course on that page we have to make sure the users know that if they set crontab to run every 5 minutes and set a post to publish at 10:13, it won't post until 10:15.

I know it takes away from the simplicity factor on using WP (some), but IMHO this would be the easiest route to getting cron running on hosts that block the fsock method. The ease factor would be reflected in the documentation on the codex page (perhaps including CPanel screenshots).

comment:11 jacobsantos6 years ago

  • Keywords has-patch removed
  • Milestone 2.9 deleted
  • Resolution set to invalid
  • Status changed from assigned to closed

I don't think the ticket is accurate, fsockopen() is claiming anything and if anything using localhost should be what would cause the rule to fail. See #4779, for more information on a similar issue.

Your firewall is broken, you should get someone to fix it. This can also be easily solved by using crontab, so closing as invalid.

comment:12 CiaranG5 years ago

  • Resolution invalid deleted
  • Status changed from closed to reopened

It's all very well saying "your firewall is broken, get someone to fix it" but as noted in the original description we are talking about a somewhat common, if misguided, configuration. I am aware of two shared hosting providers that have this setup, neither of which is prepared to even consider changing it.

I suggest that at least the filter hook be put in place (as per Nazgul's patch) in order to allow this situation to be rectified by a plugin, rather than those affected having to rely on a code hack with every new Wordpress release.

comment:13 westi5 years ago

  • Keywords reporter-feedback added; cron future removed
  • Milestone set to 2.8

Cron now uses the new multi transport HTTP code and fsockopen as a transport can be disabled.

Does this not solve the problem?

If not a filter can be added to allow for host filtering but I would do it down in the HTTP classes.

comment:14 sivel5 years ago

  • Resolution set to worksforme
  • Status changed from reopened to closed

No response in 4 months. The HTTP Transports have been updated as well as alternative cron methods for 2.8. Closing.

Note: See TracTickets for help on using tickets.