-
Notifications
You must be signed in to change notification settings - Fork 212
Implement custom database cache #4331
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Verified no excessive PMC fetches
- Verified able to update payment methods in wp-admin and immediately see them in the store front
Found a possibly redundant call to delete_option()
.
Co-authored-by: Anne Mirasol <anne.mirasol@automattic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is testing well with one minor note: we've kept the cooldown logic in effect, so we won't re-fetch data while we're in the cooldown. (This impacts step 5 in the test instructions.)
I have a lot of smaller feedback items, but I want to call out two:
- We need to make a call on whether we want prefixing for the options, and how that should work.
- We should add some guards for bad data in
is_expired()
.
It's probably worth adding an explicit link to the WooCommerce Payments code we're using to start with: https://github.com/Automattic/woocommerce-payments/blob/4b084af108cac9c6bd2467e52e5cdc3bc974a951/includes/class-database-cache.php
// Yes, there is the possibility that we attempt to write the same data multiple times within the SAME second, | ||
// and we will mistakenly think that the DB write failed. We are OK with this false positive, | ||
// since the actual data is the same. | ||
$result = update_option( $key, $cache_contents, 'no' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have multiple comments here:
- I am not sure why we're using autoload = 'no', as I believe we're expecting to need this cache regularly, so not autoloading the value is unexpected for me.
- It may have to do with other processes being more likely to fetch the value from the database later, but I still feel we should be OK with there being small timing gaps.
- It looks like we should use a boolean value in more recent versions of WordPress per the PHPDoc for
update_option
:
https://github.com/WordPress/wordpress-develop/blob/9ebba7a9aedc57d5492e409cd0aae0b6958d3642/src/wp-includes/option.php#L831-L847 - I think we should explicitly comment on why we're making whatever choice we want for this flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Autoloading too many options can lead to performance problems, especially if the
options are not frequently used. For options which are accessed across several places
in the frontend, it is recommended to autoload them, by using true.
For options which are accessed only on few specific URLs, it is recommended
to not autoload them, by using false.
The behavior was copied from the WooPayments implementation. I think it makes sense to set the autoload = false, as we are implementing this to be a general cache for the plugin; some values like the PMC are going to be needed frequently, but it might be better to allow specific values to set it to true (we can do this when we implement the prefix and test/live mode detection).
I don't have a strong opinion either way. I replaced the 'no' with false for now, but I'm happy to remove the parameter and let WordPress determine the autoload value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a super-strong opinion either, but it feels like we're fetching the payment method configurations a lot, so they may qualify for a true
value. But that does feel like something that is worth tackling in a follow-up.
/** | ||
* Setup test. | ||
*/ | ||
public function setUp(): void { | ||
parent::setUp(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should remove this -- it's a no-op.
/** | |
* Setup test. | |
*/ | |
public function setUp(): void { | |
parent::setUp(); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should still remove this method (but it's not blocking).
public static function set( $key, $data, $ttl = HOUR_IN_SECONDS ) { | ||
self::write_to_cache( $key, $data, $ttl ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may need to require or add a key prefix so we don't unintentionally overwrite or delete "real" options in the database. Requiring callers to provide valid keys would make it more work for callers, while adding a prefix would reduce the key length that we can support, and could lead to redundant option key names. That said, having a key prefix would allow for clearing all persistent cached data via a database query.
public static function set( $key, $data, $ttl = HOUR_IN_SECONDS ) { | |
self::write_to_cache( $key, $data, $ttl ); | |
} | |
public static function set( $key, $data, $ttl = HOUR_IN_SECONDS ) { | |
// Requiring a key prefix | |
if ( ! self::is_permitted_key( $key ) ) { | |
// Either return early and do nothing, or throw an exception | |
return; | |
throw new InvalidArgumentException( 'Unsupported key' ); | |
} | |
// Add key prefix -- that function would simply do something like return 'wc_stripe_db_cache_' . $key; | |
$db_key = self::get_db_key( $key ); | |
self::write_to_cache( $key, $data, $ttl ); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To reduce the changes needed in the WC_Stripe_Payment_Method_Configurations class, I just kept the prefixes we had in place; I agree we should add a prefix for the cache (wcstripe_cache_*) but we should also handle the test/live mode internally, so we can remove the multiple WC_Stripe_Mode::is_test() ternary ifs we have everytime we use the cache. I'll make a new PR for that improvement.
Co-authored-by: daledupreez <dale.du.preez@automattic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks overall solid to me.
Tested, while logging when fallback cache is used:
- when cache is expired, we fetch the PMC
- within cooldown, no fetches observed, even when reloading the payment methods page
- when cache is not expired, storefront does not trigger a PMC fetch
- after updating payment methods, fetch is observed
- no indication fallback cache had to be used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can get this shipped as-is, and then iterate from there.
Noting that I didn't retest, but I did check the changes since my last review and they look good. Also, Anne (re)tested, so I feel confident in the code.
/** | ||
* Setup test. | ||
*/ | ||
public function setUp(): void { | ||
parent::setUp(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should still remove this method (but it's not blocking).
* Add database cache class * Replace PMC cache transients with custom database cache Co-authored-by: Anne Mirasol <anne.mirasol@automattic.com> Co-authored-by: Dale du Preez <dale@automattic.com>
Fixes STRIPE-<linear_issue_id>
Fixes #4247, #4182
Changes proposed in this Pull Request:
This PR implements a custom database cache layer for persistent caching with in-memory optimization. It's based on the WooPayments Database Cache implementation class.
It's intended as a drop-in replacement of the current transient-based implementation; future PRs will move the live/test logic to the cache layer.
NOTE: It keeps the Fetch cooldown (but adds a key suffix) for now; it will be replaced with a 5-minute cache for admin pages in a future PR.
Testing instructions
WP-Admin > WooCommerce > Settings
Stripe Gateway
details pagePayment Methods
tabThe new Cache implementation uses an
option
, you can check it with:wp option get wcstripe_test_payment_method_configuration_cache
It should show something like this:
Changelog entry
Changelog Entry Comment
Comment
Post merge