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

Throw an ErrorException rather than a standard exception when an error is caught during action processing #1057

Open
wants to merge 2 commits into
base: trunk
Choose a base branch
from

Conversation

james-allan
Copy link
Contributor

Fixes #1052

Description

In the ActionScheduler_Abstract_QueueRunner::process_action() function AS sets an error handler and any E_USER_ERROR or E_RECOVERABLE_ERROR error that occurs while processing the action is caught and thrown as an exception instead.

This is super handy for WooCommerce Subscriptions because AS will trigger the action_scheduler_failed_execution action which passes callbacks the exception that was caught.

WooCommerce Subscriptions uses this hook to log data about why our subscription-related scheduled actions have failed, however something I noticed today is that because AS is creating a new exception, if you use the $exception->getFile() $exception->getLine() helpers to point to where the exception occurred, it will point to AS, not where the error was actually thrown.

This is fixed by throwing an ErrorException which enables specifying the file and line where the error occurred.

Testing instructions

  1. Add the following code snippet to your site to mimic an error occurring while processing an action.
add_action( 'action_scheduler_begin_execute', function() {
	trigger_error( 'Oops!', E_USER_ERROR );
} );

// Log the exception caught.
add_action( 'action_scheduler_failed_execution', function ( $action_id, $e ) {
	// When Action Scheduler throws an exception, it wraps the original exception in a new Exception. Information about the actual error is stored in the previous exception.
	$message = sprintf( 'a: %s in %s: %d', $e->getPrevious()->getMessage(), $e->getPrevious()->getFile(), $e->getPrevious()->getLine() );
	error_log( $message );
	ActionScheduler_Logger::instance()->log( $action_id, $message );
}, 10, 3 );
  1. Go to Tools > Action Scheduler
  2. Run any scheduled action
  3. Check your error logs or the action logs
    • on trunk you'll notice the file and line points to AS
    • on this branch it will point to where the error was thrown. ie where you put the code snippet above.
trunk This branch
Screenshot 2024-05-09 at 2 30 12 PM Screenshot 2024-05-09 at 2 30 35 PM

function ( $type, $message ) {
throw new Exception( $message );
function ( $type, $message, $file, $line ) {
throw new ErrorException( $message, 0, $type, $file, $line );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@james-allan I'm not sure this is enough (or at least, may not work as expected with recent PHP runtimes). When I test:

  • action_scheduler_begin_execute is fired from within a try {} block, and the test snippet then triggers an error.
  • We enter this error handler, and throw the ErrorException.
  • We now return to the matching catch {} block which converts the throwable (in this case, the ErrorException) into a regular exception.

So, in my own local testing, I do not see the same result you document in the testing instructions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, I tested with PHP 8.3.

Copy link
Member

@barryhughes barryhughes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it goes a little beyond the problem you are immediately trying to solve, I'm wondering if we can greatly simplify things (specifically, remove the custom error handler and the nested try structure), now that we no longer need to support PHP 5.6 🤔

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

Successfully merging this pull request may close these issues.

Use ErrorException when catching errors while processing scheduled actions
2 participants