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

Add in-memory cache to DB cache to deal with DB write failures #9639

Conversation

vladolaru
Copy link
Contributor

@vladolaru vladolaru commented Oct 28, 2024

Related https://github.com/Automattic/woocommerce-payments-server/issues/2826

Changes proposed in this Pull Request

There are situations where a WordPress site will run out of disk space and, as a consequence, all DB writes will fail, but DB reads will continue to work. You end up with a pseudo-working site that seems fine, if left untouched.

The trouble is that our DB cache entries will expire, and the system will want to refresh/re-fetch the data from our platform and attempt to write it to the DB cache - this will fail, causing each cache read to do a new fetch!!! You would think that the WP object cache would provide a backstop to this, but no; when writing a WP option with update_option, first the DB query is attempted, and only if it succeeds the data is written to the WP object cache (this behavior makes sense for the purposes of the WP object cache) - in our scenario, the new data is never written to the WP object cache.

Of course, the site is in dire need of attention from the admin, but WooPayments needs to do its best not to "throw gasoline at the problem" and also manage its API requests.

To reduce the negative side effects of this scenario, in this PR, we introduce an in-memory cache to hold the data for the duration of a request, regardless of whether it came from the DB or was fetched on the fly from our platform.

This in-memory cache functions as a backstop in case of failures to write DB options - for the remainder of the request we will use the data we got in the in-memory cache and not attempt further fetches and DB writes. As a bonus, the in-memory cache should introduce a slight performance increase since we avoid reaching the WP object cache, for sites with a working object cache, and quite a performance increase for sites with no working object cache since we avoid reaching the DB for every cache read.

Testing instructions

Prep work

  1. Checkout the develop branch in your local repo
  2. Make sure you have an onboarded account (it can be a sandboxed account) with the account data cached in the DB (you can use the WCPay Dev Tools to check)
  3. In your local repo, create a new file docker/mu-plugins/local-helpers/profiling.php with the following contents:
<?php
$get_cached_account_data_calls = 0;
$get_cached_account_data_generator_calls = 0;

add_action( 'shutdown', function() { // Use the shutdown hook to log as late as possible.
	global $get_cached_account_data_calls;
	global $get_cached_account_data_generator_calls;

	// Add Query Monitor logs.
	do_action( 'qm/debug', 'get_cached_account_data call count: ' . $get_cached_account_data_calls );
	do_action( 'qm/debug', 'get_cached_account_data_generator call count: ' . $get_cached_account_data_generator_calls );

	// Add error_log logs, if you wish to check things via the `docker/wordpress/wp-content/debug.log` file.
	$request_url = home_url() . wp_unslash( $_SERVER['REQUEST_URI'] );
	error_log( $request_url . ' get_cached_account_data call count: ' . $get_cached_account_data_calls );
	error_log( $request_url . ' get_cached_account_data_generator call count: ' . $get_cached_account_data_generator_calls );

} , -1 ); // Use -1 to get ahead of Query Monitor, which uses priority 0.
  1. Require this file from your docker/mu-plugins/0-local-helpers.php file (create it if you don't have it) by adding this line:
require_once __DIR__ . '/local-helpers/profiling.php';
  1. Make the following changes or apply as a patch to record the number of times the \WC_Payments_Account::get_cached_account_data method and its generator are called:
Index: includes/class-wc-payments-account.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php
--- a/includes/class-wc-payments-account.php	(revision cdfaaa4d3cc2c6aafc0a63de541acf94be26f86c)
+++ b/includes/class-wc-payments-account.php	(date 1730213380695)
@@ -2073,6 +2073,9 @@
 	 * @return array|bool Account data or false if failed to retrieve account data.
 	 */
 	public function get_cached_account_data( bool $force_refresh = false ) {
+		global $get_cached_account_data_calls;
+		$get_cached_account_data_calls++;
+
 		if ( ! $this->payments_api_client->is_server_connected() ) {
 			return [];
 		}
@@ -2082,6 +2085,8 @@
 		$account = $this->database_cache->get_or_add(
 			Database_Cache::ACCOUNT_KEY,
 			function () {
+				global $get_cached_account_data_generator_calls;
+				$get_cached_account_data_generator_calls++;
 				try {
 					// Since we're about to call the server again, clear out the onboarding disabled flag.
 					// We can let the code below re-create it if the server tells us onboarding is still disabled.

  1. Make sure you have the Query Monitor plugin installed and activated.

Local testing

  1. Navigate around the WordPress admin dashboard and ensure you can see the call logs in the Query Monitor panel (you can also check the docker/wordpress/wp-content/debug.log file). You should see get_cached_account_data called many times (tens or even hundreds of times), but zero calls to get_cached_account_data_generator since the account data is cached in the DB.
    Screenshot 2024-10-29 at 17 50 34
  2. Now, it is time to simulate your WP site's inability to write DB options. For this, edit the docker/wordpress/wp-includes/option.php file and add return false; in the update_option() function in two places (line 909 and 944, in the latest WP version):
if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
		return false;
	}

	/** This filter is documented in wp-includes/option.php */
	if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
+		return false; // !!! Simulate failure to write a new option !!!
		return add_option( $option, $value, '', $autoload );
	}
		}
	}

+	return false; // !!! Simulate failure to update an option !!!
	$result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
	if ( ! $result ) {
		return false;
	}

	$notoptions = wp_cache_get( 'notoptions', 'options' );
  1. Use PHPMyAdmin, edit the wcpay_account_data option in the wp_options table, and change the fetched timestamp at the end to something days in the past; the following value will suffice:
s:7:"fetched";i:1730000022;
  1. Now, your account data cache is expired and should be refreshed. Navigate the WP dashboard (or your site's frontend) and, in Query Monitor > Logs, you should see an equal number of get_cached_account_data and get_cached_account_data_generator calls (and each page loading terribly slow - tens of seconds):
    Screenshot 2024-10-29 at 18 07 37
  2. Stash your local changes (with the calls counter increments) by running the git stash command, checkout this PR's branch, and reapply the changes by running the git stash pop command.
  3. Navigate the WP dashboard (or your site's frontend) and, in Query Monitor > Logs, you should see many calls to get_cached_account_data but only one get_cached_account_data_generator calls:
    Screenshot 2024-10-29 at 18 12 53
  4. Using PHPMyAdmin, delete the wcpay_account_data option in the wp_options table. This will also cause the account data to be fetched since we have no data saved in the DB cache.
  5. Navigate the WP dashboard (or your site's frontend) and, in Query Monitor > Logs, you should see many calls to get_cached_account_data but only one get_cached_account_data_generator calls.
  6. Go to your local server repo, make sure you are on the latest trunk, and simulate the GET.accounts endpoint returning errors by adding one of the following lines here at the beginning of the endpoint controller callback \WCPay\Accounts_Controller::get_basic_account_info - you can try all of them, one at a time:
throw new Exceptions\Too_Many_Requests_Exception(); // Rate-limited response.
return rest_ensure_response( new \WP_Error( 'wcpay_authorization_failure', __( 'Sorry, you cannot access this resource.', 'woocommerce-payments' ), [ 'status' => 401 ] ) ); // Authorization failure.
return rest_ensure_response( [] ); // No account.
  1. After each server edit, navigate the client WP dashboard (or your site's frontend) and, in Query Monitor > Logs, you should see many calls to get_cached_account_data but only one get_cached_account_data_generator calls.
  2. Remove/comment-out the two return false; lines added to the docker/wordpress/wp-includes/option.php file to bring your DB back in working order.
  3. When you first refresh a page, you will see in Query Monitor > Logs one get_cached_account_data_generator call since the cache was not set and the data needed to be fetched.
  4. If you refresh the page or navigate around, you should see zero get_cached_account_data_generator calls
  5. For good measure, go to the WCPay Dev Tools page, clear the cache, and make sure it gets refreshed.

  • Run npm run changelog to add a changelog file, choose patch to leave it empty if the change is not significant. You can add multiple changelog files in one PR by running this command a few times.
  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Post merge

@vladolaru vladolaru self-assigned this Oct 28, 2024
@botwoo
Copy link
Collaborator

botwoo commented Oct 28, 2024

Test the build

Option 1. Jetpack Beta

  • Install and activate Jetpack Beta.
  • Use this build by searching for PR number 9639 or branch name update/add-in-memory-cache-to-db-cache-to-deal-with-db-write-failures in your-test.site/wp-admin/admin.php?page=jetpack-beta&plugin=woocommerce-payments

Option 2. Jurassic Ninja - available for logged-in A12s

🚀 Launch a JN site with this branch 🚀

ℹ️ Install this Tampermonkey script to get more options.


Build info:

  • Latest commit: d3654a7
  • Build time: 2024-11-01 09:11:36 UTC

Note: the build is updated when a new commit is pushed to this PR.

Copy link
Contributor

github-actions bot commented Oct 28, 2024

Size Change: 0 B

Total Size: 1.34 MB

ℹ️ View Unchanged
Filename Size
release/woocommerce-payments/assets/css/admin.css 1.37 kB
release/woocommerce-payments/assets/css/admin.rtl.css 1.37 kB
release/woocommerce-payments/assets/css/success.css 173 B
release/woocommerce-payments/assets/css/success.rtl.css 173 B
release/woocommerce-payments/dist/blocks-checkout-rtl.css 2.64 kB
release/woocommerce-payments/dist/blocks-checkout.css 2.64 kB
release/woocommerce-payments/dist/blocks-checkout.js 67.3 kB
release/woocommerce-payments/dist/cart-block.js 16.8 kB
release/woocommerce-payments/dist/cart.js 5.73 kB
release/woocommerce-payments/dist/checkout-rtl.css 1.21 kB
release/woocommerce-payments/dist/checkout.css 1.21 kB
release/woocommerce-payments/dist/checkout.js 32.8 kB
release/woocommerce-payments/dist/express-checkout-rtl.css 230 B
release/woocommerce-payments/dist/express-checkout.css 230 B
release/woocommerce-payments/dist/express-checkout.js 14.8 kB
release/woocommerce-payments/dist/frontend-tracks.js 858 B
release/woocommerce-payments/dist/index-rtl.css 39.3 kB
release/woocommerce-payments/dist/index.css 39.3 kB
release/woocommerce-payments/dist/index.js 302 kB
release/woocommerce-payments/dist/multi-currency-analytics.js 1.08 kB
release/woocommerce-payments/dist/multi-currency-rtl.css 4.46 kB
release/woocommerce-payments/dist/multi-currency-switcher-block.js 60.6 kB
release/woocommerce-payments/dist/multi-currency.css 4.46 kB
release/woocommerce-payments/dist/multi-currency.js 57.3 kB
release/woocommerce-payments/dist/order-rtl.css 730 B
release/woocommerce-payments/dist/order.css 730 B
release/woocommerce-payments/dist/order.js 42 kB
release/woocommerce-payments/dist/payment-gateways-rtl.css 1.32 kB
release/woocommerce-payments/dist/payment-gateways.css 1.32 kB
release/woocommerce-payments/dist/payment-gateways.js 38.4 kB
release/woocommerce-payments/dist/payment-request-rtl.css 230 B
release/woocommerce-payments/dist/payment-request.css 230 B
release/woocommerce-payments/dist/payment-request.js 14.2 kB
release/woocommerce-payments/dist/plugins-page-rtl.css 386 B
release/woocommerce-payments/dist/plugins-page.css 386 B
release/woocommerce-payments/dist/plugins-page.js 20.1 kB
release/woocommerce-payments/dist/product-details-rtl.css 433 B
release/woocommerce-payments/dist/product-details.css 436 B
release/woocommerce-payments/dist/product-details.js 12.1 kB
release/woocommerce-payments/dist/settings-rtl.css 11.6 kB
release/woocommerce-payments/dist/settings.css 11.5 kB
release/woocommerce-payments/dist/settings.js 224 kB
release/woocommerce-payments/dist/subscription-edit-page.js 703 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal-rtl.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.js 20.2 kB
release/woocommerce-payments/dist/subscription-product-onboarding-toast.js 730 B
release/woocommerce-payments/dist/subscriptions-empty-state-rtl.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.js 19.3 kB
release/woocommerce-payments/dist/tokenized-payment-request-rtl.css 230 B
release/woocommerce-payments/dist/tokenized-payment-request.css 230 B
release/woocommerce-payments/dist/tokenized-payment-request.js 15 kB
release/woocommerce-payments/dist/tos-rtl.css 235 B
release/woocommerce-payments/dist/tos.css 235 B
release/woocommerce-payments/dist/tos.js 21.8 kB
release/woocommerce-payments/dist/woopay-direct-checkout.js 6.14 kB
release/woocommerce-payments/dist/woopay-express-button.js 24.6 kB
release/woocommerce-payments/dist/woopay-rtl.css 4.52 kB
release/woocommerce-payments/dist/woopay.css 4.49 kB
release/woocommerce-payments/dist/woopay.js 71.6 kB
release/woocommerce-payments/includes/subscriptions/assets/css/plugin-page.css 625 B
release/woocommerce-payments/includes/subscriptions/assets/js/plugin-page.js 814 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/i18n-loader.js 2.46 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/jetpack-script-data.js 735 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/react-jsx-runtime.js 553 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/i18n-loader.js 1.02 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/script-data.js 69 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/babel.config.js 163 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.css 2.45 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.js 14.2 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.rtl.css 2.45 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.js 280 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.rtl.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.css 625 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.js 333 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.rtl.css 626 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-users.js 417 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-ajax.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-callables.js 584 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.css 215 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.css 721 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.js 412 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-users.js 621 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/about.css 1.04 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-empty-state.css 294 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css 408 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin.css 3.59 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/checkout.css 301 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/modal.css 746 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css 574 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css 414 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js 543 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js 9.4 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js 6.78 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js 3.84 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js 545 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js 2.52 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js 22.2 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js 11.7 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js 1.29 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js 507 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js 358 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js 428 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js 1.38 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js 782 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/modal.js 1.09 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js 1.26 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.css 391 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.js 3.04 kB

compressed-size-action

@vladolaru vladolaru changed the title Update/add in memory cache to db cache to deal with db write failures Add in memory cache to DB cache to deal with DB write failures Oct 29, 2024
@vladolaru vladolaru changed the title Add in memory cache to DB cache to deal with DB write failures Add in-memory cache to DB cache to deal with DB write failures Oct 29, 2024
@vladolaru vladolaru marked this pull request as ready for review October 29, 2024 16:24
@vladolaru vladolaru requested review from marcinbot and a team October 29, 2024 16:32
@vladolaru vladolaru requested a review from anu-rock October 30, 2024 12:14
Comment on lines 316 to 317
if ( isset( $this->db_cache_write_errors[ $key ] ) &&
$this->db_cache_write_errors[ $key ] > 0 &&
Copy link
Contributor

Choose a reason for hiding this comment

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

This is fairly difficult to follow, but I think I know what it's doing.

But if we get rid of the maybe_ as outlined above and always write to memory first and then attempt a DB write later, then perhaps db_cache_write_errors will be redundant? Because the $cache_contents will be whatever is in memory, so we'd catch things in the is_expired check below.

I'm hoping we could remove db_cache_write_errors and simplify things to be just one array.

Copy link
Contributor

Choose a reason for hiding this comment

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

This suggestion sounds sane to me. I cannot imagine a performance hit if we always use the in-memory cache fallback.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@marcinbot, I searched long and hard for a way to forego the use of db_cache_write_errors, but I haven't found one.

Now that we got rid of the cache size management let me explain the current logic; maybe you spot something I missed:

  • we always initialize the in-memory cache when reading (or writing) the cache.
  • we always use the data in the in-memory cache (there will be only one get_option call per key, per request), unless the cache entry is deleted or we are forced to refresh mid-request
  • if a cache entry needs to be refreshed (missing, expired, invalid, etc), we need to know if there were prior DB write failures:
    • if there were no failures, we will proceed as usual and refresh the cached data
    • if there were failures, we don't try the refresh and instead use what we have in the in-memory cache (data fetched from our platform but not written to the DB). Without knowing of the previous DB write failures, we cannot stop continuously refreshing the data on every call to get_or_add.

I don't think we have the option of making the in-memory cache sticky per an entire request because of the force_refresh logic.

Does this make sense?

Copy link
Contributor

Choose a reason for hiding this comment

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

if there were no failures, we will proceed as usual and refresh the cached data

But looking at the code, whether or not there were failures, we will then proceed to check the in-memory value and return based on that value's timestamp.

So let's say there's a DB error and we didn't have the errors array:

  • The in-memory array already has an updated value
  • The value has not been propagated to the DB, but that's ok
  • On a subsequent call within the same request, we look at the in-memory value and see that it has been refreshed recently

I think the problem might be this block, which I think we could remove since it's all about one request anyway:

if ( ! $cache_written ) {
	// If the cache write failed, mark as not refreshed.
	$refreshed = false;
}

Regarding the force_refresh flag mid-request: it seems it's being checked before the errors array so it will force the refresh regardless of the errors even in the current code.

But I haven't done any debugging. I think the way to do it would be to place some breakpoints and custom conditionals to simulate an error on update_option and see how the code behaves. You might have already done that, though, in which case I'm happy to back off :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, man! It was staring me in the face and I didn't see it - I got too caught up with errored responses, but they are not retried until the cache expires.

I removed the DB write errors handling, and it works like a charm! Tested it with correct platform responses, empty array, and errors (rate limited), all with simulated DB write failures.

Thank you for not backing off so easily, Marcin! Now, we have a truly elegant solution. Excellent!

Copy link
Contributor

@anu-rock anu-rock left a comment

Choose a reason for hiding this comment

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

Great work!


Review checklist

Parameter Result
Approach ✅ All good
Implementation 👍 A couple of observations noted above.
Automated tests 👍 Looking good, but we may need to revise them depending on whether we move away from conditional caching based on DB write errors.
Naming ✅ All good
Typing ✅ All good
Code comments 🔝 Excellent!
Changelog 👍 Almost good (left a comment)
Documentation Not applicable
PR description ✅ All good
Testing instructions 🔝 Excellent!
Manual testing ✅ Works as expected

Scenarios tested

Scenario Result Screenshot
Simulate the inability to write to DB options table ✅ Page loads became painfully slow (100+ seconds), with an equal number of get_cached_account_data and get_cached_account_data_generator calls
Switch to this PR's branch ✅ Page loads became fast again, with an only 1 call to get_cached_account_data_generator
Delete the wcpay_account_data option from DB ✅ Only 1 call to get_cached_account_data_generator
Turn off WP options simulation ✅ Only 1 call to get_cached_account_data_generator on first page load and 0 calls on subsequent page loads
Reset account cache from WCPay Dev Tools ✅ Only 1 call to get_cached_account_data_generator on first page load and 0 calls on subsequent page loads
Check the top-level Payments pages - Overview, Transaction, Disputes, Deposits, Settings ✅ No application errors related to missing account cache noted throughout my testing. All pages loaded without errors.

/**
* In-memory cache for the duration of a single request.
*
* This is used to avoid multiple database reads for the same data and as a backstop in case the database write fails,
Copy link
Contributor

Choose a reason for hiding this comment

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

Cruel nitpick: It's the first time I've come across the term 'backstop'. IMO, 'fallback' is a more common term and we should use it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nitpick reply: "Backstop" and "fallback" are not perfect synonyms. In our case, we always "pass through" the in-memory cache (as opposed to falling back on it), and, in certain cases, we don't move past it (hence being a backstop).

A true fallback is the system we have in core for Payment Gateways Recommendations: if we are allowed to fetch remotely, we will; but if we are not allowed or fail to, we fall back to using the hard-coded ones (defaults).

WDYT? 😜

Copy link
Contributor

Choose a reason for hiding this comment

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

Before (when the in-memory cache was used conditionally based on DB write errors), I thought it was a fallback to the WP options cache (not the WP cache object) in most cases.

After (now that in-memory cache is always used), 'backstop' feels more accurate. But that also means we're introducing a potentially unfamiliar term, so it's worth clarifying somewhere. Unless it's just me :)

Comment on lines 316 to 317
if ( isset( $this->db_cache_write_errors[ $key ] ) &&
$this->db_cache_write_errors[ $key ] > 0 &&
Copy link
Contributor

Choose a reason for hiding this comment

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

This suggestion sounds sane to me. I cannot imagine a performance hit if we always use the in-memory cache fallback.

Copy link
Contributor

@marcinbot marcinbot left a comment

Choose a reason for hiding this comment

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

One comment below, otherwise pre-approving!

Copy link
Contributor

@anu-rock anu-rock left a comment

Choose a reason for hiding this comment

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

LGTM :shipit:

@vladolaru vladolaru added this pull request to the merge queue Nov 1, 2024
Merged via the queue into develop with commit d100c15 Nov 1, 2024
25 checks passed
@vladolaru vladolaru deleted the update/add-in-memory-cache-to-db-cache-to-deal-with-db-write-failures branch November 1, 2024 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants