Redirects and Drupal cache

Created on 7 June 2023, over 1 year ago
Updated 4 February 2024, 9 months ago

Problem/Motivation

I have ECA enabled in a zero-new Drupal 9.5.9 installation. Created a Model that will redirect or not to somewhere, upon calling a Vocabulary's TERM page, depending on some criterion tied to the TERM entity. Things work as expected... ONCE. After that, reloading page does not help. Only a CLEAR CACHE will make it work again... for once.

Steps to reproduce

- zeroed Drupal installation, 9.5.9, PHP 8.0.26
- ECA + BPMN.io enabled
- create a taxonomy Vocabulary "X", with a LINK field "Y" as custom field to each Term Entity to be created
- insert 2 Terms, one with the LINK field filled, other with that field empty
- create ECA Model that will:
-1 be triggerd by View Content Entity, Type = Taxonomy Term, Any
-2 ask whether Bundle = X
-3 ask whether Field "Y" Is Not Empty
-4 redirect to the Link filled in the non-empty field of the Term.

Proposed resolution

...??

Remaining tasks

--

User interface changes

--

API changes

--

Data model changes

💬 Support request
Status

Fixed

Version

2.0

Component

Code

Created by

🇧🇷Brazil Marco Aurelio Rocca

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Marco Aurelio Rocca
  • 🇩🇪Germany jurgenhaas Gottmadingen

    Yes, that's what caching is supposed to do. You would face the same problem when writing php code in a module: if the first page request is cached, and another similar request is received, that will be server from cache and none of Drupal's event subscribers will ever be notified. It's the same issue that personalisation faces all the time.

    What could be a solution? Either turning off caching for such pages, or adding cache tags such that the request handler knows to handle that depending on context.

  • 🇧🇷Brazil Marco Aurelio Rocca

    Thanks you for your time, @jurgenhaas!
    I cannot say that I understood the point, but anyway I tried to figure it out with no success. Drupal installation configured, as far as I know, to prevent caching, with no effect. Tried to use Eca-Cacheabilty, using "Cache invalidate" in a couple of situations... but the interface demands sobre CACHE KEY parameter that I do not know how to provide.

  • 🇩🇪Germany jurgenhaas Gottmadingen

    The event View Content Entity is not ideal, it's not what you may expect. This is not only called when calling the entity page, but internal a lot whenever the entity is being rendered, not only on its canonical page. This topic was recently discussed here: https://www.drupal.org/project/eca/issues/3363781#comment-15086899 💬 View if User-ID or User-Mail-Address is identical otherwise redirect Closed: outdated - so you may want to change your event to Controller found to handle request and append the Route match condition.

    The cache invalidation is only available for cache entries that have previously been set by ECA as well. But not for caching in general.

    To debug that behaviour you described, you may want to look into the response headers from the Drupal site in the network tab of the development tools in your browser. That should contain some information about caching as well, and it may help you to find out what's wrong. The fact that it works after a cache clear indicates that the cache is getting into the way of ECA here.

    If you could provide us access to your test site, we could have a look, or you upload your ECA model here so that we can review it.

  • Status changed to Postponed: needs info over 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen
  • 🇧🇷Brazil Marco Aurelio Rocca

    Thanks again for your time, Jurgenhaas!

    I could not yet manage to put our site somewhere reachable by you, but I'll try to get that done.

    I could use the "CONTROLLER FOUND" as trigger, and in the sequence I used "ROUTE MATCH", set to "entity.taxonomy_term.canonical", and made a redirect action. Thus, I could kind of INTERCEPT all callings to any taxonomy terms, with a REDIRECT action.

    But that was just a drill.
    The GOAL is to intercept only Term Entities of a specific Vocabulary, where I do have a custom field with non-empty value.

    I understand that what's missing for me is a way to grasp the data about that specific Entity, which is called by the '/taxonomy/term/{taxonomy_term}'-like path.

    Does that make sense?

  • 🇩🇪Germany jurgenhaas Gottmadingen

    You can load the entity (i.e. the term) by using the route parameter and then add another sequence to check, if that term is associated with a certain vocabulary.

  • 🇧🇷Brazil Marco Aurelio Rocca

    I made an EXPORT of the last test with trigger = "controller found", and send it here.
    I dont know whether it is useful, hope so.
    I did not get ahead with the step = "load the entity (i.e. the term) by using the route parameter", because I realized that there, too, that CACHE thing is in effect. So it is in my way again... and I cant figure out why, looking at the Developers Panel :(

    What the ECA here exported do:

    1. triggers when a "Controller Is Found" action takes place
    2. checks whether or not the "Route" used is like "entity.taxonomy_term.canonical"
    3. if so, logs a message in the registry
    4. redirects towards the FrontPage

    But, again, it will only work ONCE PER TERM CLICKED. After that, it'll not work again until a Clean Cache is performed.

  • 🇩🇪Germany jurgenhaas Gottmadingen

    Confirmed, I also tried with the event Start dispatching request which is dispatched even earlier in the process, but even then, the cache is getting into our way. You can see that even without a browser by calling

    curl -I https://www.example.com/taxonomy/term/1
    

    which will show you the 302 response the first time with no cache related header values. For subsequent requests, this responds with 200 and x-drupal-dynamic-cache: HIT as one of the headers. When I disable the module Internal Dynamic Page Cache, and flush cache once, then the redirect works correctly as expected.

    This sounds like the dynamic page cache from Drupal core is somehow caching the ECA action so that it won't get executed next time, but then it responds with the full non-redirected content the second time which will then also be cached.

  • 🇩🇪Germany jurgenhaas Gottmadingen

    I've summarized that issue in Slack (see https://drupal.slack.com/archives/C1BB308HH/p1689063544676429) and hope that we get some more insight on this problem. Sounds to me like a dynamic page cache issue.

  • 🇧🇷Brazil Marco Aurelio Rocca

    Thank you so much for your efforts, @Jurgenhaas!

  • Status changed to Active over 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    Thanks to @cilefen over in the above Slack thread, it looks like we've found the reason for why this is not working: the redirect action, which is provided by Drupal core, is written such that it acts upon the response event. That is, unfortunately, far too late in the event chain and hence shows the above behaviour.

    When looking into how the redirect module does it, it became clear that they act upon the request event, which is much earlier than the response event. And then, everything works just fine.

    So, how can we resolve that? We could either try and change the core action plugin. But I doubt that's going to work because actions can be used in many different scenarios, and they have no control over the event that triggers them; could be early in the chain but also pretty late. That's why that action relies on the response event, as that will always after the action gets called.

    For ECA, that could be different. If we provided a new action for more flexible redirects, we could provide one that works on either the request or the response event, depending upon the model where it's being used. I guess, we should go for that.

  • Status changed to Needs review about 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    Turns out, there is a way to get this model to work without even providing new action plugins. Here is how the model can be designed:

    • Event: Response created - it's important to use exactly that event, as other request or response events are not suitable
    • Condition: Route match - compare the current request to the route name entity.taxonomy_term.canonical
    • Action: display message
    • Action: redirect to URL

    I was able to get this working on a production site with all caches being enabled. Both anonymous and authenticated users got always redirected and the message was always displayed as expected too.

    @Marco Aurelio Rocca could you please give this a try and let us know if that works for you too?

  • 🇩🇪Germany jurgenhaas Gottmadingen
  • 🇧🇷Brazil Marco Aurelio Rocca

    Thank you, @jurgenhaas!
    I'll try that as soon as possible!
    If I get it right, would be better to try it after updating to 2.0.x-dev.

  • 🇧🇷Brazil Marco Aurelio Rocca

    It works!
    Action triggered by
    event = RESPONSE CREATED,
    condit = ROUTE MATCH compared to "entity.taxonomy_term.canonical",
    Action=LOGS MESSAGE
    + Action = REDIRECT do frontpage.

    Navigated to a Taxonomy list of terms, clicked them repeteadelly, log messagens are recorded several times and navigation is redirected to frontpage, not for once only but repeatedly.

    Thank you so much!

  • Status changed to Fixed about 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    Thanks for your feedback, glad we've sorted this out. Will add something about this to the ECA Guide.

  • Automatically closed - issue fixed for 2 weeks with no activity.

  • Status changed to Fixed 9 months ago
  • Any thoughts on how one might restrict results by limiting the route to a specific node?

    I've tried:

    Action triggered by
    event = RESPONSE CREATED,
    condit = ROUTE MATCH compared to "entity.node.canonical"
    Token: Load Route Parameter = "/node/{node}"
    condition = Token value IS SpecifiedNodeID
    Redirect

    But the token isn't loading anything. I've tried every variation of {node}/{node_id}, variations on node/preview/{node_preview}/{view_mode_id} using canonical, and everything else I can extrapolate from the node.routing.yml, but nothing works. Is this the right way to attach a routing parameter here?

  • Kindly disregard my previous question. I was overthinking. A regular token calling [current-page:url:unaliased:path] did the trick.

  • I've run into a new problem with this solution. For reasons I don't understand, it's causing all my layout builder pages to throw an Ajax loadjs error after login. This seems to be a conflict with Big Pipe, because the issue goes away when I remove either big pipe or delete the ECA modal and comes back when both are installed together.

    The console error looks like this:

    An error occurred during the execution of the Ajax response: LoadJS
      (anonymous) @ js_[hash].js?scope=footer&delta=0&language=en&theme=mytheme&include=[hash]:58
      Promise.catch (async)
      Drupal.Ajax.success @ js_[hash].js?scope=footer&delta=0&language=en&theme=mytheme&include=[hash]:58
      processReplacement @ js_[hash].js?scope=footer&delta=2&language=en&theme=mytheme&include=[hash]:67
      checkMutationAndProcess @ js_[hash].js?scope=footer&delta=2&language=en&theme=mytheme&include=[hash]:67
      (anonymous) @ js_[hash].js?scope=footer&delta=2&language=en&theme=mytheme&include=[hash]:67
      processMutations @ js_[hash].js?scope=footer&delta=2&language=en&theme=mytheme&include=[hash]:67

    I'm seeing the behavior in both chrome and firefox. Attached a basic modal example for review.

Production build 0.71.5 2024