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

feat: add event queue debug #34

Merged
merged 4 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions DEV_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ For example, the `reader_registered` event will create or update a WP User in th

The Hub can also be an active site in the network. So events that happen on the Hub should also be propagated as if it was just another node.

But when an event is fired in the Hub, there's no need to send a webhook request to itself. So we simply listen to events fired by the Data Events API and trigger the process to persist it into the `Event_Log`. This is done by `Hub\Event_Listeners` and it basically does the same thing `Hub\Webhook` does, but it is listening to local events instead of receiving webhook requests from a Node.
But when an event is fired in the Hub, there's no need to send a webhook request to itself. So we simply listen to events fired by the Data Events API and trigger the process to persist it into the `Event_Log`. This is done by `Hub\Event_Listeners` and it basically does the same thing `Hub\Webhook` does, but it is listening to local events instead of receiving webhook requests from a Node.

## Nodes pulling events from the hub

Expand Down Expand Up @@ -109,20 +109,15 @@ All log messages will include the process id (pid) as the first part of the mess

### When an event is fired in a Node

Newspack Network will listen to the Newspack Data Events API, which has its own way to dispatch events asynchronously. If Woocommerce is installed, it will use the Action Scheduler lib, otherwise it will simply dispatch a dedicated request to process the event.
Newspack Network will listen to the Newspack Data Events API.

So before we can even begin to follow the event through the Newspack Network flow, it needs to be dispatched. Sometimes it can take one or two minutes.

You can inspect it in the `Tools > Scheduled Actions` panel if Woocommerce is active, and the Data Events API will also output plenty of information in the logs.

When the event is finally dispatched in a Node, it will create a new webhook request. See [Data Events Webhooks](https://github.com/Automattic/newspack-plugin/blob/master/includes/data-events/class-webhooks.php) for details on how it works.
When an event dispatched in a Node, it will create a new webhook request. See [Data Events Webhooks](https://github.com/Automattic/newspack-plugin/blob/master/includes/data-events/class-webhooks.php) for details on how it works.

In short, a webhook is a Custom Post type post scheduled to be published in the future. Once it's published, the request is sent. If it fails, it schedules itself again for the future, incresing the wait time in a geometric progression.

When the event is dispatched, you should not see anything special in the logs. Everything is handled by webhooks, so you can:
* Go to Newspack > Connections > Webhooks and see if the request was scheduled there
* Manually check the requests on the database
* Manually dispatch requests using `Newspack\Data_Events\Webhooks::process_request( $request_id )`
You can see the scheduled webhook requests in Newspack Network > Node Settings under the "Events queue" section.

* If you want to manually and immeditally send a webhook request, you can do so using `Newspack\Data_Events\Webhooks::process_request( $request_id )`

When the request is sent, Webhooks will output a message starting with `[NEWSPACK-WEBHOOKS] Sending request` in the logs.

Expand Down
101 changes: 101 additions & 0 deletions includes/node/class-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace Newspack_Network\Node;

use Newspack_Network\Admin;
use Newspack_Network\Crypto;

/**
* Class to handle Node settings page
Expand Down Expand Up @@ -259,7 +260,107 @@ private static function render_debug_tools() {
<input type="hidden" name="action" value="<?php echo esc_attr( Pulling::MANUAL_PULL_ACTION_NAME ); ?>">
<button class="button"><?php esc_html_e( 'Synchronize data', 'newspack-network' ); ?></button>
</form>

<?php

self::render_webhooks_requests();

}

/**
* Renders the table with the scheduled webhooks requests.
*
* @return void
*/
private static function render_webhooks_requests() {
$secret_key = self::get_secret_key();
if ( ! $secret_key ) {
// Node is not configured yet.
return;
}

$requests = \Newspack\Data_Events\Webhooks::get_endpoint_requests( Webhook::ENDPOINT_ID );

?>
<h3>
<?php esc_html_e( 'Scheduled Events', 'newspack-network' ); ?>
</h3>
<p>
<?php esc_html_e( 'The following events are scheduled to be sent or have recently been sent to the Hub.', 'newspack-network' ); ?>
</p>
<table class="wp-list-table widefat fixed striped table-view-list">
<thead>
<tr>
<th scope="col" id="date" class="manage-column column-date">Date</th>
<th scope="col" id="action_name" class="manage-column column-action_name">Action name</th>
<th scope="col" id="data" class="manage-column column-data">Data</th>
<th scope="col" id="data" class="manage-column column-status">Status</th>
<th scope="col" id="data" class="manage-column column-status">Errors</th>
</tr>
</thead>

<?php
foreach ( $requests as $request ) :
$status_label = __( 'Pending', 'newspack-network' );
$icon = '🕒';
if ( 'finished' === $request['status'] ) {
$status_label = __( 'Sent', 'newspack-network' );
$icon = '✅';
}
$r = json_decode( $request['body'], true );
$data = Crypto::decrypt_message( $r['data'], $secret_key, $r['nonce'] );
$date = gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $r['timestamp'] );
$scheduled_for = gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $request['scheduled'] );
?>

<tr>
<td><?php echo esc_html( $date ); ?> (#<?php echo esc_html( $r['request_id'] ); ?>)</td>
<td><?php echo esc_html( $r['action'] ); ?></td>
<td><code><?php echo esc_html( $data ); ?></code></td>
<td>
<?php echo esc_html( $icon . ' ' . $status_label ); ?>.
<?php
echo esc_html(
sprintf(
/* translators: %s: scheduled date */
__( 'Scheduled for %s', 'newspack-network' ),
$scheduled_for
)
);
?>
</td>
<td>
<?php if ( ! empty( $request['errors'] ) ) : ?>
<?php
echo esc_html(
sprintf(
/* translators: %s is the number of errors */
_n(
'There was %s failed attempt to send this request',
'There were %s failed attempts to send this request',
count( $request['errors'] ),
'newspack-network'
),
count( $request['errors'] )
)
);
echo '<ul>';
foreach ( $request['errors'] as $error ) {
echo '<li><code>';
echo esc_html( $error );
echo '</code></li>';
}
echo '</ul>';
?>
<?php endif; ?>
</td>
</tr>

<?php endforeach; ?>
</table>

<?php

}

}