I'm using Message module for a "activity stream" type feature on my site. We have ~15k users and a couple hundred activity related messages get created every day.

I'm moving the previous "activity feed" code from views, into entity_load_multiple() and entity_view(_multiple)() type heuristic, which I'm trying to use all over my site for caching related reasons.

I have a horribly slow dev machine (linux guest under virtualbox, under a linux host) on purpose which helps debug "speed" issues because, well the box is slow. Using XHProf to drill down on problems.

I'm currently using a type of "infinity scroll", which loads up the next 10 messages in a persons queue and spits them out. This request takes roughly 2-3 seconds on my slow dev machine.

1 second of this is because of Message::buildContent() which calls token_replace().

Through out my entire site, token is one of the worst offenders for speed in Drupal. This appears to also be effecting Message performance as well.

Could it not be possible (not sure if it already is possible) to cache the post tokenized output and store it along with the EntityCache for the message. It could be keyed against the messages "timestamp" or something similar?

Just curious if this is a crazy idea, or if it's something that's already possible and I'm missing using caching of check_markup().

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

RoySegall’s picture

Did you define the message tokens to be dynamically? For example in your message text did you used [node-ref:title]? if so, every time the message is displayed then the label of the node is pulled from the DB. If you will uses @{node-ref:title} this will hard coded the node title will increase performance.

Entity cache is another option for caching but what about using views + Views infinite scroll and caching the results? Didn't try this, but it sound to me like a good direction.

drone.ah’s picture

I have a similar issue with slow rendering of messages due to relatively heavy use of tokens.

Where can I set the message tokens to be dynamic? I tried changing from [token] to @{token} within the message text(s) but it just renders it as @{token}.

For example, changing [message:field-game:title] to @{message:field-game:title} now renders just @{message:field-game:title}. field_game is an entity reference field on the message type.

The views result could be cached but the result is per user and there is poor support for "per-user" caching with views.

I hacked together a quick solution which generates a hash and stores the output and any generated css in the cache and then uses that if available.

This patch is attached...

In the view that I am using which renders ~50 items, it went from around 3,000ms to around 100ms :-D

RoySegall’s picture

I don't think we need patch for that - maybe an integration with the Entity cache module which i don't think is needed because there is a generic integration with any entity.

The idea of dynamic tokens is every time the message is being displayed the token is being rendered on the fly(load the entity etc. etc. etc.).
Hard coded tokens say that once the message is being created, the token is being rendered and the value is saved on the message and every time the message will be displayed the rendering of the token will be spared.

This is a good idea if you have fields that their value won't be changed for a lond time, title of a node, name of user, and if they will be changed then you need to work on a logic that will change the hard coded value.

amitaibu’s picture

@drone.ah can you benchmark your View after enabling entity-cache module?

Also, as RoySegall suggests, maybe you should not use tokens but hardcoded arguments.

j0rd’s picture

Drone.dh's patch looks promising.

--

My solution would be more to cache the output of check_markup(), thus having a hybrid of dynamic render everytime and cache.

Thus when the cache_filter table is cleared and the message is re-outputed, it would get re-generated.

This is how page nodes cache output with tokens.

check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE);

--

Currently it doesn't appear message module is using cache_markup to do it's output rendering, but I assume it could.

At the end of the day, it needs to be up to the developer our fine grained they need their cache. Standard Drupal caches are a very heavy hammer, and usually you need to roll your own caches or at least your own cache invalidation.

--

As mentioned on my site, I do not use page or block caching. Everything on the site is geotargetted, and unique per user. This includes my "infinite scroll" of messages, which is generated per user based of people they "follow" (ala twitter). Caching the output of the view is not very feasible with 15,000 users, since each view output is different. Thus I need to cache the messages.

What isn't different though, is that multiple users see the same messages in their "feed". Thus caching of messages for me makes sense.

If I have to invalidate {cache_filter} table every time something in that messages token gets updated, I can do that. Or some other cache, but what I can't do is parse these tokens every time the message gets outputted, as it's simply too slow.

(PS. I rolled my own db_query() version of "views infinite scroll" which does the same thing, but is much faster, this is the last step into optimizing it)

RoySegall’s picture

It's true that the default caching mechanism of views it's not prefect for unique results. We had to deal with that when creating a views caching for OG content so @amitaibu wrote a module for that: Views OG cache.

drone.ah’s picture

Entity cache is already enabled - and the messages are still slow. In fairness, I just realised that each message has to process 13 tokens and the issue lies with the token replacement than with message...

We use views grouping which means that infinity scroll and the like just doesn't work...

I am using standard tokens as opposed to the dynamic ones. There are already hundreds of thousands of messages in the system and I did not see an easy way to retroactively add the dynamic token information to the messages. There is of course, also the issue that if we later find that we need another bit of information, we would need to go through and re-do the dynamic tokens.

Caching is not an ideal solution either. This stems largely from the fact that the initial render is still slow.

How easy would it be to make it possible to map a standard token to a dynamic token and the store the value of the token on save?

If we map the same logic to iterate through previous messages (possibly just a VBO setup), the backward data population requirement could also be met.

This would seem to provide the best of both worlds?

bluegeek9’s picture

Status: Active » Closed (outdated)