параллельная и фоновая задача в эликсире? - PullRequest
0 голосов
/ 07 октября 2018

У меня есть функция в контроллере, которая отправляет массивные текстовые сообщения. (1000 сообщений) функция контроллера выглядит следующим образом ..

def send_sms(conn, _params) do
  // code is abbreviated
  # Spawn new process for sending message and saving to database
  spawn(fn -> send_message_and_save(user, recipients, phone_numbers) end)
  // code is abbreviated
end

и эта функция

def send_message_and_save(user, recipients, phone_numbers) do
    // code is abbreviated 
    results = Sms.send_sms_with_messaging_service_async(phone_numbers, recipients.message, msg_sid, status_callback, account, token)

    case Sales.confirm_order(recipients, attrs) do
      {:ok, %{id: order_id, user_id: user_id}} ->
        Messenger.create_message_status(results, order_id, user_id)
        # Update Bitly status as Saved
        if is_nil(recipients.bitly_id) do
        else
          bitly = Texting.Bitly.get_bitly_by_id(recipients.bitly_id)
          Bitly.confirm_changeset(bitly) |> Bitly.update()
        end
        {:ok, "Message sent successfully. Your analytics data will be updated shortly."}
      {:error, _changeset} ->
        {:error, "Can't send message!"}
    end
end

Процедура заданиякак в функции send_message_and_save 1. Отправьте 1000 сообщений, используя внешний запрос API.- Я сделал это с помощью Task.Supervisor. async_stream / 6 2. confrim_order (пометить схему заказа как «подтвержденное» состояние и обновить (обновить) 3. create_message_status (операция создания) 4. get_bitly_by_id (операция получения) 5Bitly.confirm_changeset и Bitly.update (операция обновления)

В этой процедуре будет выполнено всего 5000 операций с базой данных. После выполнения запроса к внешнему API-запросу будет три запроса обратного вызова состояния длямой веб-сервер для каждого из внешних запросов API. Это означает, что отправка 1000 сообщений будет 3000 тысяч операций обновления для схемы message_status (принять, доставлено или недоставлено).

Таким образом, отправка 1000 сообщений приведет к 8000 операций базы данных, и яЕсли попытаться это сделать, мой веб-сайт становится вялым и пропускает некоторые запросы о состоянии обратного вызова на мой веб-сайт из-за тайм-аута (внешний API говорит: «Есть много причин, по которым может возникнуть тайм-аут соединения; частыми причинами являются длительные запросы к базе данных или внешние процессы и вызовы»).на внешние системы, которые долго возвращаются ")

Итак, как я могу улучшить эту ситуацию?как я могу спроектировать это правильно?Пожалуйста, помогите: (

1 Ответ

0 голосов
/ 08 октября 2018

Я бы начал с использования ETS в качестве кэша - вы знаете всю информацию, которую вам нужно будет извлечь из БД заранее, поэтому продолжайте и загружайте ее в память.Затем вы можете ускорить процесс, который будет отвечать за таблицу ETS, и выполнить все последующие запросы к таблице в памяти, что будет намного быстрее, чем несколько вызовов БД для каждого пользователя, которому необходимо отправить сообщение.Обратите внимание, что таблицы ETS доступны только локально **, но если вы включите их в процесс, этот процесс будет доступен глобально, как и любой другой процесс OTP.

Многие приложения имеют узкое место в своей базе данных, поэтомучем меньше работы вы можете дать вашей базе данных, тем лучше (для многих систем).

** локально означает локальный для узла.Если вы запускаете свое приложение только на одном сервере, то все локально, и вам не придется много думать об этом.Если вы когда-нибудь планируете кластеризовать свое приложение, вам нужно обернуть таблицу ETS в процесс с помощью API.Процессы имеют уникальные адреса во всех кластеризованных узлах BEAM, поэтому вы можете использовать этот API для получения доступа к таблице в памяти.В большинстве случаев вы можете рассматривать ETS как более быструю повторную передачу.На высоком уровне это одно и то же, но ETS использует термины erlang / elixir, поэтому у него нет накладных расходов на сериализацию строк, как у redis, что делает его намного быстрее.

...