Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
mazz opened this issue Jun 2, 2024 · 0 comments
Open

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

mazz opened this issue Jun 2, 2024 · 0 comments

Comments

@mazz
Copy link

mazz commented Jun 2, 2024

Environment

  • Elixir & Erlang/OTP versions (elixir --version): elixir:1.14.4-erlang-25.3-alpine-3.17.2
  • Operating system: ubuntu 18.04
  • Pigeon version: 2.0.0.rc2

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:

  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)})}")

              data_map = %{
                "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"
              }

              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
    end
  end

Previously we would use the convenient handle_push() update() remove() put_mutable_content() put_content_available() 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant