Forum Academy Marketplace Showcase Pricing Features

Performance Q&A guide

Hello,
I have one more question: what happens if two workflows concurrently modify the same field of the same object (for instance to increase a number by 1) ?
Do you run workflows in sequences or is it parallelized (multi-threaded) in some way ?
If it is multi-threaded, do you have kind of “locks” that prevent an action from modifying a field if another user is already modifying it ? If so, does it happen at action or workflow level ? (ie, between two actions of the same worfklow, can we assume that all used objects have not been modified by another user ?)

Thanks !

Workflows run from the same web browser session are run in sequence to avoid two workflows modifying the same field (we run them in parallel if it’s safe to do so). Unfortunately, we don’t have good controls / locks for two workflows run by different users or browsers, so you can get issues if two different users try to add one to the same number at the same time. That’s on our to-do list to build, since it would make life easier to be able to offer strong guarantees about what will happen in those cases.

@josh thanks for all the great info in this thread. It has been really helpful.
Is there a simple way to add the loading icon to the blank white page similar to the bubble work environment in the attached photo? It is so much better than users staring at a blank white page and seems like it should be easy to do.

3 Likes

Thanks for the answer, i am looking forward to it!

@josh Am I right to assume that the searches used on the page are being updated as the workflows run, so it’s possible for a reference in a workflow to suddenly shift to a different thing mid-workflow?

Like, if I have ReusableElementA in cell 3 of a Repeating Group. The Repeating Group’s list comes from a search for Thing1 that meet certain criteria. If I use a workflow to start making changes to the Thing1row5 of cell 3, and part-way through those changes Thing1row5 no longer matches the criteria of the Repeating Group’s list, then the list will update and a different Thing1 will move up to cell 3. That would mean that the references to “ReusableElementA’s Thing1” would switch mid-workflow.

No, we try to freeze a “state of the universe” at the beginning of a workflow execution, and only reflect changes when the workflow explicitly modifies something. Things like a cell in a repeating group showing a different thing we don’t count as an explicit change. That said, our rules for how exactly that works aren’t great: they’re pretty complicated (I sometimes have to read the actual Bubble source code to predict how a particular situation will play out), and they don’t handle interactions between workflows well (if two different users modify the same data at the same time, the end result might ignore the changes made by one of the users), so this is fairly high on our todo list to overhaul: I’d like to be in a place where we have a clear, easily understandable set of guarantees we can make about how data will behave.

2 Likes

@josh is Bubble smart enough to grab data delivered for another element rather than run the search again?

Like if I have a Repeating Group that loads a list of thing-A, and each thing-A has a field with thing-B, so each cell needs to go get the right thing-B for each cell. Am I right in thinking that the call for each thing-B happens after the list of thing-As is loaded?

But, what if I’ve already delivered a bunch of thing-Bs to another element on the page? Will Bubble know that it doesn’t have to go all the way back to the server to get the thing-B?

Could you also explain what happens when we call “repeating group A’s List of Items:count” ? Is that optimized in some way even if the repeating group is not showing all data ?

Also, what happens if the app shutdowns during a workflow for instance because reach too much server capacity usage (error 400) ? DO we obtain a half completed workflow ?

1 Like

Great thread. Our app pulls several images from multiple cameras, and loading each image is a bit slow (.5~1s) but once the image is loaded the first time, it’s cached and loads much faster on subsequent views. How could we cache all of these images for the user when the page is loaded? Would this be a good idea or might it hurt more than help?

Here’s our demo: https://app.barnowl.tech/demo

Note: if you click the camera name in the slideshow (CAM1/CAM2 etc), I have a popup of all images belonging to that camera. As you can see, once they all download, the slideshow is extremely fast, but only for that camera’s images.

Any other optimization advice would be hugely appreciated, thanks again!

1 Like

I made a 1x1 pixel repeating group on each camera which downloads and caches all of its images. Simple fix and the app is now lightning fast.

EDIT: It’s actually lightning fast on desktop, but still pretty slow on mobile as if it’s not caching the images.

Try it yourself, anything I could do about this? Thanks

1 Like

Next to in-app performance enhancements, I’d like to reboot the server location question again. I know the choice of server location is currently not an option in non-dedicated plans, but I really hope you will consider this in the very near future as I’d rather stay on a non-dedicated plan that keeps more money in Bubble’s pocket than to go dedicated.

I’m curious to learn 2 things:

  1. Do the differences in download speed between the Oregon server and the Frankfurt server justify going dedicated?
  2. What are other users experiencing connecting to these servers (what is normal?)

I did the following network tests:

  1. Kiev - Oregon server http://cloudharmony.com/speedtest-for-aws:ec2-us-west-2
  2. Kiev - Frankfurt server http://cloudharmony.com/speedtest-for-aws:ec2-eu-central-1
  3. Amsterdam - Oregon server http://cloudharmony.com/speedtest-for-aws:ec2-us-west-2
  4. Amsterdam - Frankfurt server http://cloudharmony.com/speedtest-for-aws:ec2-eu-central-1

Results:

1. Kiev - Oregon
Down 4 threads
1,28
Down 2 threads
3.09
Latency
397

2. Kiev - Frankfurt
Down 4 threads
9.79
Down 2 threads
35.17
Latency
97

3. Amsterdam - Oregon
Down 4 threads
1,62
Down 2 threads
13.44
Latency
379

4. Amsterdam - Frankfurt
Down 4 threads
25,56
Down 2 threads
93,23
Latency
34,5

I have a repeating table where I have date field. It’s seem that it’s causing a lot of slowdown on loading. If I remove them, this go a lot faster. I try to remove all other stuff one by one in the page to see impact on loading time, but only date field make a difference. What can I do to solve this?

I have a large array of searches to run. Basically one for each combination of a day and a data point. They’re in a set of nested repeating groups.
All I need to know is that there’s at least one search result. That way I know the condition is satisfied. I don’t care if there is more than one result that satisfies the same condition.

I’d prefer that the system stop searching after it finds a single result.
@josh If I build the expression like this

search:first item:convert to list:count

Then will the search stop after it finds one result?

1 Like

Hi @blueback09 , yes, that will expression will work: it will retrieve at most one result. However, this will also work:

search: count > 0

Bubble is smart enough to recognize that pattern and load at most 1 item from the search.

In general, I would recommend expressing things as simply as possible. The most simple way of doing things isn’t always the fastest, but it often is, and we are constantly working to write database optimizations that take common patterns and rewrite them behind the scenes to be fast. The more complicated your expression is, the more likely our query optimizer won’t know what to do with it, and will just run it in a naive fashion instead of doing something intelligent.

3 Likes

Okay, thanks. So, rephrasing it to confirm understanding: if I have a condition like “greater than 0” on the count of a search, Bubble will automatically optimize it to stop searching after it’s flipped the condition from “no” to “yes”?

Does the same thing apply if I’ve got one element that has “search:count” in it and a different element has a condition “first element’s value > 0”?

I’ve been breaking up the logic into more and more discrete elements as I try to push Bubble to do things outside of its comfort zone. Sometimes I’ve got chains of logic almost a dozen elements long, each one handling a different part of the logic tree. Does that inherently confuse Bubble’s optimization, or does it all kind of get flattened so it can still be optimized?

Yes, more or less. Bubble might also choose to just fetch the total count without fetching any of the individual items, depending.

Yes, same as above (in this case it will likely fetch the total count).

It depends. Also, we’re always changing things. Rather than trying to memorize a set of (changing) rules, my advice is to test empirically in situations where performance is critical. Create a test page, with nothing on it except for the search(es) you want to investigate. Then use a tool such as Chrome’s developer tools (https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#record) to look at the requests we send to the server. Requests that fetch data are send to the /elasticsearch/get, /elasticsearch/mget/, /elasticsearch/search, and /elasticsearch/msearch (before anyone asks, no, we don’t use elasticsearch… we used to, and the endpoint names are a legacy holdover from that). By looking at the response the server sends (and the size of the response), you can see how much data it takes Bubble to load a given search.

5 Likes

From my actual experience it is important to start development with one rule in mind:

Mobile performance and responsiveness first! From scratch!

Everything else comes second!

I had also performance problems and then i asked myself: What is the main problem? Its easy to say that some tech is the reason. In my case i was understanding simply this: my development workflow is wrong! Im the problem!

Because today most websites and apps will be used on mobile devices and often loaded over mobile phone networks. From my experience also the javascript rendering in mobile web browsers is slower. This means finaly: If you start with performance and responsiveness questions in the middle or end of your development, you will get endless problems!

What does that mean in practice? What you can do?

  • Most of all: use a smartphone with mobile phone network connection (not WiFi !) and a mobile browser as your main test screen. From beginning! After every development step reload the app on your smartphone over the mobile phone network. You will see problems instantly.

  • If you have a nice idea in mind, what the app could show your users and you see that this idea needs too much loading or rendering or database search time: make the idea simpler or forget the idea. The best idea makes no sence if your user will not see your idea fast.

  • Make the index/ home/ landing page as fast as possible.

  • Experiment with different settings if you have a performance problem and doesnt find the reason. For this just clone a whole page or app and then delete step by step every group and element. On every step reload the smartphone. At the latest here you will find your performance brakes.

  • And for the maintenance of your app:
    A) Dont repeat yourself. Instead ask yourself from the beginning how you can reuse elements and data. As example: The design of your app you can manage often globally with database entires, costum states or under the “Styles” button. This way you dont need to change the appearance of every single element if you want to try later something new. You do this globally for a bunch of elements, the whole page or the whole app.
    B) Name every element clear. Same for every data type and data field. You will find already used elements and data much faster in the elements tree or for dynamic data requests.

Sure also the Bubble platform self needs to be better and faster with the time. Same for every technology. No questions. But my point is: Before pointing on the technology, ask what yourself maybe doing wrong. Start with question your own development workflow! Like i did. On this way you will avoid not all, but much problems on the core :slight_smile:

8 Likes

How do the privacy roles impact performance? For example, if the amount of records are reduced due to privacy roles, will the search performance improve?

2 Likes

Hope @josh is still around to answer performance questions :slight_smile:

Your answer to the same search:

Made me wonder follow-up questions:

  • Say you need current user’s thing’s thing’s {field A/B/C…} – and you need them in various places (elements, workflows, another search that relies on that dynamic data) … is it still okay to do search for a thing in each place? If so, how does Bubble smartly know the data? Is there some sort of cache system so even after the search is over on page load, that same searched data can be used on later workflows?

  • Would there be a performance payload/difference between two methods? 1) Do a search for in every place it needs, 2) Do a search for in one group or repeating group and other places reference that one source of truth?

I’d assume that: since the search requires two steps into the thing (user’s thing’s thing…), it would be better to have one group that holds that thing (current user’s things’ thing) and other elements and events/actions reference that group. That way I feel like Bubble doesn’t have to go in two steps to find that data every time.

3 Likes

Just a follow up, is search for still the most fast way to reference things. Along with that, does it matter which order the contraints are in.
Say I have a spoons (1000 total spoons) (red, Blue, green) in a drawer (50 total drawers) (kitchen drawer, buttler drawer) in a house (10 total houses) (my house, your house) and I want to search for a blue spoon in the buttler pantry of your house would the search constraints work better like

spoon = blue
drawer = buttler
house = your house

or

house = your house
drawer = butler
spoon = blue

3 Likes