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

[API Pull] Tweak Variations Notifications #2450

Merged
merged 10 commits into from
Jul 8, 2024

Conversation

puntope
Copy link
Contributor

@puntope puntope commented Jul 3, 2024

Changes proposed in this Pull Request:

This PR tweaks the logic for notifications when handling variations. In particular:

  • FIXED: We were sending create notifications for variations when the parent was not published still
  • FIXED: We were only sending delete notifications for the parent when a variation was deleted.
  • FIXED: SOme unhandled exceptions when we try to access. a product that is not in the database anymore.

Detailed test instructions:

  1. Checkout PR
  2. Test that creation/update/deletion of simple product works as always
  3. Create a Variable Product and generate variations for It
  4. Go to Woo - Status - Scheduled actions - That step should not schedule any notifications
  5. Asign price to some of the variations and publish the product
  6. Go to Woo - Status - Scheduled actions - See scheduled notifications create for the variations with price + the variable product
  7. Run the actions and see if they are logged in the gla log under Woo - Status - logs
  8. Edit one of the variations without price
  9. It doesn't schedule or log anything as it was not created yet
  10. Remove one of the variations without price
  11. It doesn't schedule or log anything as it was not created yet
  12. Edit one of the variations with price
  13. Go to Woo - Status - Scheduled actions - See scheduled notifications update for the variations with price + the variable product. Run them
  14. Remove the variation with price
  15. Go to Woo - Status - Scheduled actions - See scheduled notifications update for the variations with price + the variable product and one delete notification in the logs (directly without schedule) for the one you deleted with offer_id
  16. Set the variable product as DONT SYNC AND SHOW
  17. Go to Woo - Status - Scheduled actions - See scheduled notifications delete for the variations with price + the variable product
  18. Before running it. Go back and set the variable product as SYNC AND SHOW
  19. Go to Woo - Status - Scheduled actions - See scheduled notifications update for the variations with price + the variable product
  20. Run the delete notifications of the step 17
  21. See in the logs they are not logged (a filter prevented it, because we set is as visible in step 18)
  22. Run the tasks from step 19
  23. See them logged in the log
  24. Try to delete products and variations in different ways to see if everything is handled properly.

Additional details:

Changelog entry

@github-actions github-actions bot added the changelog: tweak Small change, that isn't actually very important. label Jul 3, 2024
@puntope puntope self-assigned this Jul 3, 2024
src/Product/SyncerHooks.php Outdated Show resolved Hide resolved
Copy link

codecov bot commented Jul 3, 2024

Codecov Report

Attention: Patch coverage is 80.00000% with 7 lines in your changes missing coverage. Please review.

Project coverage is 64.7%. Comparing base (7ff8a9e) to head (f03a407).
Report is 33 commits behind head on feature/google-api-project.

Additional details and impacted files

Impacted file tree graph

@@                      Coverage Diff                       @@
##             feature/google-api-project   #2450     +/-   ##
==============================================================
+ Coverage                          64.6%   64.7%   +0.1%     
- Complexity                         4552    4560      +8     
==============================================================
  Files                               473     473             
  Lines                             17757   17769     +12     
==============================================================
+ Hits                              11478   11501     +23     
+ Misses                             6279    6268     -11     
Flag Coverage Δ
php-unit-tests 64.7% <80.0%> (+0.1%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
src/Jobs/Notifications/ProductNotificationJob.php 100.0% <100.0%> (ø)
src/Product/ProductHelper.php 92.1% <100.0%> (+0.2%) ⬆️
src/Product/SyncerHooks.php 90.0% <90.5%> (+5.3%) ⬆️
...Jobs/Notifications/AbstractItemNotificationJob.php 88.4% <37.5%> (-11.6%) ⬇️

... and 3 files with indirect coverage changes

);

if ( $product instanceof WC_Product && $this->product_helper->has_notified_creation( $product ) ) {
$this->notifications_service->notify( NotificationsService::TOPIC_PRODUCT_DELETED, $product_id, [ 'offer_id' => $this->product_helper->get_offer_id( $product_id ) ] );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For post deletions, it is better to send the notification directly.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it better to send the notification directly instead of scheduling the job?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because otherwise, it can be the case that the item is not in the database (for example, the user trash the product and deletes it from the trash before the action runs). In this cases an exception might happen or we cannot get anymore the product props.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation. However, this could be problematic because if you delete multiple products or a variable product with many variations (say 30), we'll end up making all the requests simultaneously. From the merchant's perspective, it will take a while to delete a product with multiple variations because all the requests need to be completed. Also, we could reach the API rate limit.

As far as I can tell, we only need to notify the product ID, topic, and offer_id, so can't we just schedule the job to notify that? Or do we need the actual product?

@puntope puntope marked this pull request as ready for review July 3, 2024 14:17
@puntope puntope requested a review from a team July 3, 2024 14:17
Copy link
Contributor

@jorgemd24 jorgemd24 left a comment

Choose a reason for hiding this comment

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

Hi @puntope, thanks for fixing this. However, I found some issues:

Edit one of the variations without price
It doesn't schedule or log anything as it was not created yet
Remove one of the variations without price
It doesn't schedule or log anything as it was not created yet
Edit one of the variations with price

Not sure if I'm doing this right or understanding this part, but I see notifications scheduled for all the variations with prices, as well as for the parent.

Edit one of the variations with price
Go to Woo - Status - Scheduled actions - See scheduled notifications update for the variations with price + the variable product. Run them

I am unsure if this is ideal because we only updated one variation. Will Google make X (number of variations + parent product) REST API requests? It seems unnecessary to make so many requests. For example, if a product has 30 variations and only 1 is updated, we'll schedule 30 + 1 jobs, and the merchant will receive 31 API requests?

Also, I left some comments about the code, and it doesn't seem like we've added tests to check which variations need to be notified.

$this->handle_notified( $topic, $item );
try {
if ( $this->can_process( $item, $topic ) && $this->notifications_service->notify( $topic, $item, $data ) ) {
$this->set_status( $item, $this->get_after_notification_status( $topic ) );
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we update the PHPDocs to set_status and the other functions it calls to indicate that this method can throw an "InvalidValue" exception? Otherwise, it's hard to know which methods might throw the exception. From what I can see, the exception will be thrown here:

protected function get_item( int $item_id ) {
return $this->helper->get_wc_product( $item_id );
}

*
* @return string The offer id
*/
public function get_offer_id( $product_id ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The rest of the file includes argument types. Should we add the type for $product_id as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adjusted here 9e041f5

'topic' => NotificationsService::TOPIC_PRODUCT_DELETED,
]
);
$this->schedule_delete_notification( $product );
Copy link
Contributor

Choose a reason for hiding this comment

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

Not needed for this PR but maybe we could have similar methods for schedule_update_notificationand schedule_create_notification

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now, we are only calling those in that place. schedule_delete_notification was refactored to avoid code duplication.

);

if ( $product instanceof WC_Product && $this->product_helper->has_notified_creation( $product ) ) {
$this->notifications_service->notify( NotificationsService::TOPIC_PRODUCT_DELETED, $product_id, [ 'offer_id' => $this->product_helper->get_offer_id( $product_id ) ] );
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it better to send the notification directly instead of scheduling the job?

@puntope
Copy link
Contributor Author

puntope commented Jul 5, 2024

  • but when I restore the simple product, we send an UPDATE topic instead of a CREATE topic.

Good catch. Fixed here. 413c7c5

@puntope
Copy link
Contributor Author

puntope commented Jul 5, 2024

I am unsure if this is ideal because we only updated one variation. Will Google make X (number of variations + parent product) REST API requests? It seems unnecessary to make so many requests. For example, if a product has 30 variations and only 1 is updated, we'll schedule 30 + 1 jobs, and the merchant will receive 31 API requests?

Seems like when we did activate the MC Push again we forgot to handle that
https://github.com/woocommerce/google-listings-and-ads/blob/develop/src/Product/SyncerHooks.php#L180

I did some tweaks for it also. Now should be trigger per variation and parent only.

See ff8468e

@puntope
Copy link
Contributor Author

puntope commented Jul 5, 2024

Thanks @jorgemd24 for all your feedback. I applied some changes. Can you take another look?

@puntope puntope requested a review from jorgemd24 July 5, 2024 12:37
Copy link
Contributor

@jorgemd24 jorgemd24 left a comment

Choose a reason for hiding this comment

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

Hi @puntope, thanks for the adjustments. It is working well and I'm getting the right results. However, I have one concern about making the request to the Notification endpoint directly instead of scheduling the job when deleting the item. See my comment.

Let me know if you would prefer to address this in this PR or a follow-up PR.

Thanks!

if ( $this->notifications_service->is_ready() ) {
$this->handle_update_product_notification( $products[0] );
}

foreach ( $products as $product ) {
Copy link
Contributor

@jorgemd24 jorgemd24 Jul 7, 2024

Choose a reason for hiding this comment

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

At this point, everything should be an instance of WC_Product. However, as an extra precaution, should we add a check like this before continuing with the loop: if (!$product instanceof WC_Product) continue;? I meant in these lines:

protected function handle_update_products( array $products, $notify = true ) {
$products_to_update = [];
$products_to_delete = [];
foreach ( $products as $product ) {
$product_id = $product->get_id();
// Avoid to handle variations directly. We handle them from the parent.
if ( $this->notifications_service->is_ready() && $notify ) {
$this->handle_update_product_notification( $product );
}

);

if ( $product instanceof WC_Product && $this->product_helper->has_notified_creation( $product ) ) {
$this->notifications_service->notify( NotificationsService::TOPIC_PRODUCT_DELETED, $product_id, [ 'offer_id' => $this->product_helper->get_offer_id( $product_id ) ] );
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation. However, this could be problematic because if you delete multiple products or a variable product with many variations (say 30), we'll end up making all the requests simultaneously. From the merchant's perspective, it will take a while to delete a product with multiple variations because all the requests need to be completed. Also, we could reach the API rate limit.

As far as I can tell, we only need to notify the product ID, topic, and offer_id, so can't we just schedule the job to notify that? Or do we need the actual product?

@puntope
Copy link
Contributor Author

puntope commented Jul 8, 2024

As far as I can tell, we only need to notify the product ID, topic, and offer_id, so can't we just schedule the job to notify that? Or do we need the actual product?

The logic know uses get_item that needs the product from DB. We can refactor that in future iterations. Since DarkL is next week I would suggest to have it working even if the performance is not the optimal.

p.s I also added the check for WC_Product. This is ready for a new round.

@puntope puntope requested a review from jorgemd24 July 8, 2024 07:35
Copy link
Contributor

@jorgemd24 jorgemd24 left a comment

Choose a reason for hiding this comment

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

Thanks for the adjustments is looking good.

The logic know uses get_item that needs the product from DB. We can refactor that in future iterations. Since DarkL is next week I would suggest to have it working even if the performance is not the optimal.

Yes I think we should give priority to this part as it can degrade the performance when deleting multiple products.

@puntope puntope merged commit 0ba7fcd into feature/google-api-project Jul 8, 2024
12 checks passed
@puntope puntope deleted the tweak/notifications-variations branch July 8, 2024 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog: tweak Small change, that isn't actually very important.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants