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

dev/core#1674: fix rebuilding of container on every request #16919

Merged
merged 4 commits into from
Apr 1, 2020

Conversation

jaapjansma
Copy link
Contributor

Overview

The civicrm container should be cached and build once. However if an extension is installed and enabled and it does not contain the directories Civi/Api4/Event/Subscriber and Civi/Api4/Service/Spec/Provider the container is rebuild upon every request.

This ia non-functional change.

Before

The civicrm container is rebuild upon every request.

After

The civicrm container is loaded from cache.

How to test

  1. Install an extension which does not contain the mentioned directories. E.g. civirules
  2. Check whether CiviCRM still works.

Comments

This fixes API4 functionality in CiviCRM Core. I will also provide a separate PR for the api4 extension. However I am also convinced that this should not be in core at all.

See also https://lab.civicrm.org/dev/core/-/issues/1674

@civibot civibot bot added the master label Mar 28, 2020
@civibot
Copy link

civibot bot commented Mar 28, 2020

(Standard links)

@colemanw colemanw changed the title [NFC] dev/core#1674: fix rebuilding of container on every request dev/core#1674: fix rebuilding of container on every request Mar 29, 2020
@colemanw
Copy link
Member

Since this PR does alter executable source code (and as you said yourself in the description "This fixes API4 functionality in CiviCRM Core"), I'm removing the NFC label. See these PR docs for more on the subject, and please let me know if they are unclear.

@jaapjansma
Copy link
Contributor Author

@colemanw could you do PR review?

@eileenmcnaughton
Copy link
Contributor

@jaapjansma if this is a regression (as you indicate) it should go against the rc branch. Having said that it's probably better to wait for @colemanw to take a look at the best place to cache this.

@eileenmcnaughton
Copy link
Contributor

@colemanw can you look at this before the next rc is cut?

@jaapjansma
Copy link
Contributor Author

I have submitted a new PR against the 5.23 branch, is that wou meant against the RC?
See: #16934

@colemanw
Copy link
Member

I think this makes sense but I'd like to get input from @totten

@totten
Copy link
Member

totten commented Apr 1, 2020

Ooooh. I was a bit confused at first because nothing in the previous code directly suggested that it would rebuild non-existent directories. But digging into DirectoryResource.php confirms the matter:

    public function isFresh($timestamp)
    {
        if (!is_dir($this->resource)) {
            return false; // To wit: a non-existent directory will force a rebuild
        }

I'm giving this some r-run to see if other cache update scenarios work the way this is expected to. (To wit: if you create the directory and add files, then it should update. If you delete the directory or files, then it should update. But if the directory/file-listing is stable, then it should remain cached.)

@jaapjansma
Copy link
Contributor Author

Regarding when a directory is added/removed in an extension this would probably happen when someone updates an extension and a cache clear is a common action to do after updating extensions. And I believe that it does this automatically

Conceptually, you want to:

* (A) Keep the container cache when nothing has changed (regardless of whether that status-quo has an API4 subscriber folder).
* (B) Update the cache if Civi/Api4/Event/Subscriber/*.php has been newly created
* (C) Update the cache if Civi/Api4/Event/Subscriber/*.php has been newly removed

To test this out, I hacked `Civi\Core\Container::loadContainer()` to emit a debug message
to indicate if it is reusing the cache or updating. Then, I prepared two terminals for running alternate steps:

* In terminal 1, go back and forth with adding/removing folders/files like `Civi/Api4/Event/Subscriber`.
* In terminal 2, periodically run `cv ev 'echo "Hello\n";'` and note whether the cache is update.

In this way, we can see if a developer action (adding a file) leads to an automatic update in the cache.

I found that the previous commit fixed (A) and did (C), but it failed to
update per (B).  This commit should handle (A), (B), and (C).
@jaapjansma
Copy link
Contributor Author

Thanks @totten for doing this more in a symfony way!

@eileenmcnaughton
Copy link
Contributor

@totten I'm on the fence about master vs rc for this - I would lean rc but it's so close to release date - however, if it feels very safe to you I would go rc

@totten
Copy link
Member

totten commented Apr 1, 2020

@jaapjansma Cheers :)

Yeah, there's a little known setting CIVICRM_CONTAINER_CACHE which determines the caching behavior. With the extra commit, I think CRM_Api4_Services will be compliant with the setting . That setting allows 3 modes:

  • always => Always use the container cache, even if it's stale. Updates only come when there's an explicit flush. This is the best option for performance, but worst for DX, and slightly more brittle with certain extension-updates.
  • never => Never use the container cache. This is best for DX but worst for performance.
  • auto (current default) => Monitor the timestamps of relevant files. Update container cache if timestamps change. This is almost the best of both worlds (with small compromises on perf and DX)... as long as the FileResource/DirectoryResource stuff is setup well. (A problem like dev/core#1674 certainly spoils it.)

@eileenmcnaughton - I view it as moderately safe after running a few different use-cases. My initial gut would be master (5.25 / May) but I'm not opposed to 5.24 (April).

@eileenmcnaughton
Copy link
Contributor

@totten I think either is fine since it's not super recent - tests have passed - shall we merge?

// about the directory's existence, which would make it redundant with the
// newer "file_exists()" guard. However, the actual "catch()" seems broader,
// and I don't see anything in DirectoryResource that throws the exception.
// So... maybe it's not needed, or maybe there's some additional purpose.
Copy link
Member

Choose a reason for hiding this comment

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

@totten to address this question, the above try/catch was added in #15765 specifically to address the directory not existing. That was its only purpose so if it's now redundant I would say yes this can be removed.

Copy link
Member

Choose a reason for hiding this comment

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

@colemanw Cool. I've cleaned up that bit and re-tested.

@totten totten merged commit 566b10b into civicrm:master Apr 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants