maz

maz

Upgrading to Pigeon 2.0.0-rc.2 Spike in CPU usage

After upgrading from Pigeon.LegacyFCM to Pigeon.FCM, there is a massive spike in CPU usage when sending push notifications to 7000+ devices.

Here is the new Pigeon 2 code:

  defp do_send_push_message(client_devices, message) when is_list(client_devices) do
    tokens =
      client_devices
      |> Enum.map(fn x ->
        x.firebase_token
      end)
      |> Util.compact()

    chunked_tokens = Enum.chunk_every(tokens, 500)

    Enum.each(chunked_tokens, fn chunk ->
      Logger.info("chunk length #{inspect(%{attributes: length(chunk)})}")

      # dbg(chunk)

      data_map = %{
        "deep_link_route" => message.deep_link_route,
        # "short_url" => message.short_url,
        "media_type" => message.media_type,
        "org_id" => message.org_id,
        "thumbnail_path" => message.thumbnail_path,
        "thumbnail_url" => message.thumbnail_url
      }

      Enum.each(chunk, fn x ->
        n =
          Pigeon.FCM.Notification.new(
            {:token, x},
            %{"title" => message.title, "body" => message.message},
            data_map
          )

          # dbg(n)
        push = FaithfulWord.FCM.push(n)
        # dbg(push)
      end)
    end)
  end

Previously we would use the convenient handle_push() update() and remove() found in LegacyFCM, but they are no longer there.

Any suggestions as to what I’m doing wrong here?

Here is the previous code that would not cause a cpu spike:

  def send_push_message_media_music_now(
        push_message: %PushMessage{} = message,
        media_music_uuid: media_music_uuid,
        org_id: org_id
      ) do
    case Repo.get_by(MediaMusic, uuid: media_music_uuid) do
      nil ->
        Logger.info(
          "could not find media music with id: #{inspect(%{attributes: media_music_uuid})}"
        )

      media_music ->
        Logger.info("found media music with id: #{inspect(%{attributes: media_music_uuid})}")

        case Ecto.Query.from(c in ClientDevice, where: c.org_id == ^org_id) |> Repo.all() do
          nil ->
            Logger.info(
              "could not find client devices with org_id: #{inspect(%{attributes: org_id})}"
            )

          client_devices ->
            # do_send_push_message(client_devices, message)
            tokens =
              Enum.map(client_devices, fn x ->
                x.firebase_token
              end)

            chunked_tokens = Enum.chunk_every(tokens, 500)

            Enum.each(chunked_tokens, fn chunk ->
              Logger.info("chunk length #{inspect(%{attributes: length(chunk)})}")

              chunk
              |> Pigeon.LegacyFCM.Notification.new()
              |> Pigeon.LegacyFCM.Notification.put_notification(%{
                "title" => message.title,
                "body" => message.message
              })
              |> Pigeon.LegacyFCM.Notification.put_data(%{
                "push_message_uuid" => message.uuid,
                "deep_link_route" => message.deep_link_route,
                "short_url" => message.short_url,
                "media_type" => message.media_type,
                "media_format" => media_music.media_format,
                "media_path" => message.media_path,
                "media_url" => message.media_url,
                "media_id" => message.media_id,
                "thumbnail_path" => message.thumbnail_path,
                "thumbnail_url" => message.thumbnail_url,
                "mutable-content" => true,
                "version" => "1.3"
              })
              |> Pigeon.LegacyFCM.Notification.put_mutable_content(true)
              |> Pigeon.LegacyFCM.Notification.put_content_available(true)
              |> Pigeon.LegacyFCM.push(on_response: &handle_push/1)
            end)
        end
    end
  end
  def handle_push(%Pigeon.LegacyFCM.Notification{status: :success} = notif) do
    to_update = Pigeon.LegacyFCM.Notification.update?(notif)
    Logger.info("handle_push to_update #{inspect(%{attributes: to_update})}")

    to_remove = Pigeon.LegacyFCM.Notification.remove?(notif)
    Logger.info("handle_push to_remove #{inspect(%{attributes: to_remove})}")
    Enum.each(to_remove, fn remove_token ->
      case get_client_device_for_token(remove_token) do
        nil ->
          {:error, "invalid_client_device_token"}

        remove_device ->
          Repo.delete(remove_device)

          Logger.info(fn ->
            "Device #{remove_device.id} for token #{remove_device.firebase_token} has been removed"
          end)

          {:ok, remove_token}
      end
    end)

    # do the reg ID update and deletes
  end

  def handle_push(%Pigeon.LegacyFCM.Notification{status: other_error}) do
    # some other error happened
    Logger.info("handle_push other_error #{inspect(%{attributes: other_error})}")
  end

Most Liked

maz

maz

done!

Where Next?

Popular in Questions Top

sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New

Other popular topics Top

yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement