WIP: Builder Lag: Massive CPU Spikes when working with dynamic data

@charaf Fellow plugin dev here so I’m happy to dig into this if needed, but It took a while to try and track this down, still not quite sure I understand the extent of what is happening, but I have narrowed it for all purposes to dynamic data renders.

In the attached videos/screenshots you can see it happen.

  1. Created a counter element.
  2. Added non dynamic data, you can see it call the REST API for render_element I believe, near instant.
  3. Paste a dynamic data echo function that simply returns a static integer as the start or end value for the counter.

I immediately see dozen + AJAX requests, clicking through appears its triggering a resave on nearly ever element to the root, maybe sibling trees too, not sure.

  1. If you then try to edit said {echo:} function calls, it starts making the same dozens of AJAX requests for every keystroke or 2 (live rendering I assume).

  2. Once dynamic props are on the element, you can modify any field not containing dynamic props and the issue doesn’t occur. If you start typing in a field with dynamic values though it goes nuts.

This quickly stacks up hundreds of requests, bringing even an extremely over powered server to a crawl as each of them slowly finishes or 504 timeouts.

First image is showing that it not only maxed out one node, but 3 nodes. Each node is 10 CPU cores (XEON Gold) and 10GB memory, x3.

You can see the entire process recorded in chrome dev tools network tab. Cut the video as it was several minutes to finish all of them successfully. You can see how this would be painful editing experience, as the editor is nearly useless at the time these requests are processing.


Here would be my recommendations based on SAAS & WP experience:

  1. Set up your ajax calls to be cancellable.
  • On client side, every request should be stored and abortable. This should be be used in a few ways:
  • On server side, either ensure your disabling ignore_user_abort during your requests, or explicitly use methods to check if the connection is still active during your processes, bailing as soon as you detect its not, do so with things like connection_aborted() or even connection_status() != CONNECTION_NORMAL.
  1. Any time an element is saved, the requests object should be stored in a keyed object/cache, but before any save, you first check if there was a previous request object in the cache for that element, and if its still running, abort it before making another.

  2. Any time an element is moved or deleted, cancel pending requests for that element etc.

  3. Any time the browsers stop button is clicked, or esc pressed when no element is selected, all pending should abort.

  4. Add a debounce or throttle to your AJAX saves in general.

This is how major SAAS systems handle forms such as Remix.run: Network Concurrency Management | Remix

while (TRUE) {
  if(connection_aborted()) {
      break;
  }
  sleep(5);
}
var xhr = $.ajax({
    type: "POST",
    url: "some.php",
    data: "name=John&location=Boston",
    success: function(msg){
       alert( "Data Saved: " + msg );
    }
});

//kill the request
xhr.abort()

Overall we love Bricks, we have pages that not only look great but take less than 50-100kb to load, but the broken ajax in the editor for several versions now has made this an unbearable experience most times.

Please let me know what other useful info might help solve this once and for all, but I think the above are sound solutions either way for ongoing performance improvements.

Reach out to me directly, twitter, email, Post Status slack, here IDC, lets fix this.

13 Likes