aungmyooo2k17

aungmyooo2k17

I have a live view application that displays exchange rates data. Within the application, there is a box called “announcement” which shows scheduled or adhoc messages. Sometimes the message consists of around 3 lines, but occasionally it can be longer. However, the message box can only display up to 3 lines. So, when the message exceeds 3 lines, I decided to implement a scrolling animation behavior.

Here’s how I implemented it:

First, I added a Phoenix Hook to listen for when the message box is loaded. If the message box is loaded, I assume that there is a message to display.

Hooks.MessageBox = {
  mounted() {
    updateAnimationForMessage("message", this);
  },
  updated() {
    updateAnimationForMessage("message", this);
  },
};

Then, I added a JavaScript function to check the number of lines in the current message.

  const messageList = document.querySelector("#message-list");
  const content = messageList.querySelector("li:first-child");
  const cssCompute = window.getComputedStyle(content);
  context.pushEvent(event, {
    number_of_lines: Math.floor(
      parseInt(cssCompute.height) / parseInt(cssCompute.lineHeight)
    ),
  });
}

In the LiveView, I created a list with 10 rows of <li>Message here</li> elements using a for loop. These messages are scrolled up using CSS animation set to run infinitely. I push the number of lines count to the LiveView. The LiveView receives the number of lines and adds the CSS animation with inline styling.

["animation: message-slideup #{calculate_message_animation_time(number_of_lines) * 10}s linear infinite"]

I expected this code to work without any unexpected behavior or increased CPU usage. However, when I deployed it to production, I noticed that the CPU usage doubled with 200 clients accessing the application. Therefore, I am seeking help to resolve this issue.

Showing Posts 1 to 7

ibarch

ibarch

Since this is a purely cosmetic effect, maybe you can fully implement it on the client side without extra roundtrips to the server?

Hooks.MessageBox = {
  mounted() {
    const numberOfLines = calculateNumberOfLines("message", this);
    const animationTime = calculateMessageAnimationTime(numberOfLines);
    this.style.animation = `message-slideup ${animationTime}s linear infinite`;
  },
  updated() {
    // same as mounted()
  },
};
aungmyooo2k17

aungmyooo2k17 OP

Actually my message content div is inside Surface.LiveComponent. So that live view is updated this view every
30s because I run the genserver to update my message every 30s so message animation is not smooth when I do this on javascript.

<div id="message-content">
  <ul id="message-list">
    <li :for={{ _x <- Utils.get_message_loop(10) }}>{{get_in(@message, [:text])}}</li>
  </ul>
</div>
thomas.fortes

thomas.fortes

What is the frequency of updateAnimationForMessage? If it’s running something like requestAnimationFrame and you’re pushing an event from there the event is hitting the server at least 60 times a second (more in high refresh rate monitors), which for 200 users would be 12000 events a second that the server has to handle, which would explain the memory use.

I agree with @ibarch, you probably should figure out a way to decouple the animation from the roundtrips to the server.

If it is only running a single time the problem isn’t in the javascript and we would need more info about your problem to figure out where the bottleneck is.

aungmyooo2k17

aungmyooo2k17 OP

Please note that the code provided is not the complete code; it is only a reference to understand the problem. Thank you.

I have a message box component called Surface LiveView. Here’s an example of how it looks:

defmodule MessageBox do
  property(message, :map, default: %{})

  def render(assigns) do 
  ~H"""
    <div id="message-content">
      <ul id="message-list">
        <li :for={{ _x <- Utils.get_message_loop(10) }}>{{get_in(@message, [:text])}}</li>
      </ul>
    </div>
  """  
  end
end

I have a GenServer that updates the @message every 30 seconds and calls the broadcast function to notify the LiveView about the updated message:

messages = get_message_from_db()
MyWeb.Endpoint.broadcast!(
  "message:" <> tv_id,
  "show_message",
  %{message: messages}
)

In my handle_info function, I simply update the message:

socket =
  socket
  |> assign(:message, message)

The GenServer broadcasts the updated messages every 30 seconds, so the socket assignment will be called every 30 seconds. This means that the LiveView will update the HTML code every 30 seconds.

If I add code to add animation using JavaScript, the Phoenix Hooks function is called when the update happens, which resets my animation if it hasn’t finished yet.

thomas.fortes

thomas.fortes

What does messages = get_message_from_db() return? A single message or a list of all previous messages? If it is a list of all previous messages it would make the memory grow pretty fast since each liveview would have a massive @message assign in each liveview, if that’s the case you can look at something like stream to keep them out of the server.

(Even if it returns only the last message, the @message assign will grow each 30s with each client keeping the full list of messages since they connected stored in the server).

Edit: I should not answer when I’m almost asleep, I swear that I thought that the problem was a RAM and not a CPU one, so feel free to ignore it, but CPU usage isn’t exactly a problem as long as the system is still responsive.

aungmyooo2k17

aungmyooo2k17 OP

I am implementing an automatic scrolling behavior for a that contains a large amount of text. When I add the following function:

function myFunction() {
  const element = document.getElementById("message-content");
  let x = element.scrollLeft;
  let y = element.scrollTop;
  
  element.scrollTop += 1;
  setTimeout(myFunction, 10);
}

The text within the starts shaking while it moves. I am seeking help on how to handle or debug this issue.

This code that I added to my project is exactly same with the below link w3school don’t shaking but mine does.

ibarch

ibarch

Try to apply phx-update="ignore" attribute to the parent container and fill it with dummy values on LW mount.
If the scrolling runs smoothly, then it’s likely that Morphdom patching is interfering with your manual DOM updates in the hook. To resolve this issue you can try to configure Morpdom to carry over some properties during patching:

const liveSocket = new LiveSocket("/live", Socket, {
  ...,
  dom: {
    onBeforeElUpdated(fromEl, toEl) {
      if (fromEl.matches(".parent")) {
        // I'm not sure which properties need to be moved from fromEl to toEl
      }
    }
  }
});

If animation jittering remains intact you need to debug your JS implementation.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews