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

Adding a basic cache-flushing mechanism #11

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from

Conversation

nicholasio
Copy link

@nicholasio nicholasio commented Oct 2, 2017

Introduces a basic cache flushing mechanism. #4.

Copy link
Owner

@stevegrunwell stevegrunwell left a comment

Choose a reason for hiding this comment

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

I dig the general approach of caching the rather-static site details, but it looks like this PR is implementing some very specific logic to a framework that's meant to be rather agnostic by default.

What are your thoughts on additional filtering within the Thing::build() method to enable additional, potentially-cached content before any other queries are run? This could give site-specific code the ability to change the values returned from the cache, potentially solving the same problem in a more isolated way.

As always, thank you for your pull request and please accept my apologies that I missed the notification email!

@@ -7,6 +7,13 @@

namespace Schemify\Schemas;

define( 'MINUTE_IN_SECONDS', 60 );
Copy link
Owner

Choose a reason for hiding this comment

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

Rather than redefining these values in ThingTest.php, they should be added to the test bootstrap file for easy re-use.

* @param int $post_id The post being updated.
*/
function update_post_cache( $post_id ) {
wp_cache_delete( sprintf( 'schema_%s', $post_id ), 'schemify' );
Copy link
Owner

Choose a reason for hiding this comment

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

Is there a reason this isn't leveraging the get_key() function defined just above it?

* @return string A cache key to be used with the WP object cache.
*/
function get_key( $object_id, $object ) {
return sprintf( 'schema_%s', $object_id );
Copy link
Owner

Choose a reason for hiding this comment

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

If $object isn't being used, we don't really need it as an argument.

'posts_per_page' => 5000
) );

foreach ( $author_posts as $post_id ) {
Copy link
Owner

Choose a reason for hiding this comment

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

This could be further simplified to leverage the update_post_cache() function you wrote above:

array_map( __NAMESPACE__ . '\update_post_cache', $author_posts );

This eliminates the foreach loop and allows us to leverage functionality we've already defined.

Functional programming: so hot right now

) );

M::userFunction( 'wp_cache_get', array(
'times' => 1,
Copy link
Owner

Choose a reason for hiding this comment

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

I've recently learned this lesson the hard way, but you want to use the 'times' argument sparingly when testing — if you're expecting a result to match the return value of a function call, it can be assumed that the function was called. Counting the number of times it was called is usually not particularly helpful, unless it's more of a "I need to make sure this function was called X number of times, because it has other side effects."

For example, consider the following functions:

/**
 * Create a heading.
 *
 * @param string $text The text for the new heading.
 * @return string A new <h1> element.
 */
function make_heading() {
  track_headings( $text );

  return '<h1>' . shout( $text ) . '</h1>';
}

/**
 * Convert a string to uppercase and append exclamation marks.
 *
 * @param string $string The string to modify.
 * @return string The string but, you know, louder.
 */
function shout( $string ) {
  return strtoupper( $string ) . '!!!';
}

/**
 * Keep track of headings being used on the page.
 *
 * By the time I wrote this, the example was going off the rails a bit. Sorry 'bout that.
 *
 * @global $all_headings
 *
 * @param string $heading The heading text.
 */
function track_headings( $heading ) {
  global $all_headings;

  $all_headings[] = $heading;
}

When testing make_heading(), we don't necessarily care that shout() was called, as long as the result is what we expect:

public function test_make_heading() {
  $this->assertEquals(
    '<h1>THIS IS A HEADING!!!</h1>',
    make_heading( 'this is a heading' )
  );
}

Since track_headings() doesn't have an effect on the output, however, we may want to ensure that gets called:

public function test_make_heading_calls_track_headings() {
  M::passthruFunction( __NAMESPACE__ . '\track_headings', array(
    'times' => 1,
    'args'  => array( 'this is a heading' ),
  ) );

  make_heading( 'this is a heading' );
}

I'll be the first to admit that I've been overzealous about using WP_Mock for :allthethings: in the past, and the result has been tightly-coupled tests that break if any detail of the implementation changes. Hopefully I can serve as a cautionary tale! 😄

Copy link
Author

@nicholasio nicholasio Oct 27, 2017

Choose a reason for hiding this comment

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

To be honest, I'm not a huge fan of WP_Mock, it's boring to mock all those basic functions and I always have the feeling that the tests are biased and it's not really testing anything, The only reason I added times was because I was seeing it being used across tests. I'm totally fine removing it. if you think it makes sense :)

For these tests, if the function call doesn't happen the test will fail anyway, so times is not that important here.

@@ -191,7 +195,11 @@ protected function build( $post_id, $is_main ) {

// Cache the result (top-level only) so we don't have to calculate it every time.
if ( $is_main ) {
wp_cache_set( $cache_key, $data, 'schemify', 0 );
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$data['cached'] = date( 'Y-m-d H:i:s' );
Copy link
Owner

Choose a reason for hiding this comment

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

If the date of the cache time is stored in the {$cache_key}_last_update cache, why duplicate it here?

Copy link
Author

Choose a reason for hiding this comment

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

The cache expires after 12h. So the post might not chang but cache can still expire. For debug purposes that date was meant to be when the cache was recreated and not when the post was last updated

@nicholasio
Copy link
Author

nicholasio commented Oct 27, 2017

@stevegrunwell I pushed some changes to address your feedback! Thanks for you time looking into this.

By adding filtering on Thing::build() you mean moving the cache purging logic to cache.php by hooking into those filters/actions? If so that makes sense to me, I only kept the logic there because there was already some caching logic there. Let me know what you think.

@nicholasio
Copy link
Author

nicholasio commented Jan 30, 2018

Merging the latest changes here, I'll take another pass and recreate the tests.

@stevegrunwell are you still open to merge this PR?

@stevegrunwell
Copy link
Owner

@nicholasio Definitely still open, my time on Schemify has been really scattered. Hoping to be able to get back to this towards the end of this week :)

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.

2 participants