Size: a a a

2020 August 17

AB

Alex Bubnov in ErlangRus
Serg
Добрый день

Elixir-новичкам помогают тут?


Имею на erlang+cowboy рабочее приложение подменяющее асинхронное взаимодействие синхронным:

1. принял запрос с фронт устройства/браузера X в cowboy
2. отправил http-запрос во внешнюю систему Y, получил в ответе ref
3. сохранил PID-коннекта с X и ref от Y в ETS-таблице {ref_from_y, pid_from_x}
4. через cowboy_loop handler вывешиваю соединение(=процесс X) для ожидания ответа от внешней системы Y

5. Внешняя система Y шлет в cowboy http-запрос с ref
6. В ETS по ref ищу  PID-процесса который держит коннект с устройством X
7. шлю сообщение в указанный процесс PID ! {some_msg_fromY} на фронт/устройство

Есть задача перейти на Elixir/Phoenix.

Вопрос: какой инструмент/модуль Elixir/Phonenix использовать для построения такого взаимодействия?

Почитал про Task/Agent/Job/Flow  - ни один не подходит. Все равно приходится ETS + Process.send использовать как в erlang ... В какую сторону копать?
в фениксе(и plug в целом) всё очень печально с асинхронными хэндлерами.
если не вдаваться в подробности, я бы рекомендовал либо использовать голый ковбой, либо запатчить plug на проброс и обработку implementation-specific возвратов из хэндлера, позволяющих даунгрейд до голого ковбоя.
источник

AB

Alex Bubnov in ErlangRus
второй вариант я сам рассматривал, он выглядит не феноменально сложным, хотя там полно корнер-кейсов
источник

S

Serg in ErlangRus
Alex Bubnov
в фениксе(и plug в целом) всё очень печально с асинхронными хэндлерами.
если не вдаваться в подробности, я бы рекомендовал либо использовать голый ковбой, либо запатчить plug на проброс и обработку implementation-specific возвратов из хэндлера, позволяющих даунгрейд до голого ковбоя.
Спасибо.
источник

AB

Alex Bubnov in ErlangRus
корень проблемы в том, что в плаге отстутствует малейшее упоминание рантайм-среды и в особенности процессов.
с одной стороны - это типа как благое начинание, с другой - когда это нужно, всё сразу становится очень плохо.
источник

AB

Alex Bubnov in ErlangRus
Serg
Добрый день

Elixir-новичкам помогают тут?


Имею на erlang+cowboy рабочее приложение подменяющее асинхронное взаимодействие синхронным:

1. принял запрос с фронт устройства/браузера X в cowboy
2. отправил http-запрос во внешнюю систему Y, получил в ответе ref
3. сохранил PID-коннекта с X и ref от Y в ETS-таблице {ref_from_y, pid_from_x}
4. через cowboy_loop handler вывешиваю соединение(=процесс X) для ожидания ответа от внешней системы Y

5. Внешняя система Y шлет в cowboy http-запрос с ref
6. В ETS по ref ищу  PID-процесса который держит коннект с устройством X
7. шлю сообщение в указанный процесс PID ! {some_msg_fromY} на фронт/устройство

Есть задача перейти на Elixir/Phoenix.

Вопрос: какой инструмент/модуль Elixir/Phonenix использовать для построения такого взаимодействия?

Почитал про Task/Agent/Job/Flow  - ни один не подходит. Все равно приходится ETS + Process.send использовать как в erlang ... В какую сторону копать?
о, слушай, я вспомнил
короче, есть в стдлибе эликсира умеренно подходящая вещь - Stream.resource.
грубо говоря, твоё ожидание ответа можно описать как ожидание значения из стрима.
источник

S

Serg in ErlangRus
источник

AB

Alex Bubnov in ErlangRus
именно. внутри next_fun ты пишешь свой receive, и хэндлер повиснет в нем
источник

S

Serg in ErlangRus
в примере источник - файл. а в моем случае источник - callback request от внешней системы...
источник

AB

Alex Bubnov in ErlangRus
в start_fun ты собственно кидаешь запрос и регистрируешь self() как получателя ответа.
источник

AB

Alex Bubnov in ErlangRus
в next_fun - как я уже сказал, receive.
источник

AB

Alex Bubnov in ErlangRus
схема не очень красивая, но должна работать в принципе
источник

S

Serg in ErlangRus
Stream.resource(
fn ->
  {:ok, ref_from_ext_api} = HTTPOISON.request to ExtAPI
  pid = self()
  pid
end,

fn pid ->  
  do receive
    {ref_from_ext_api, params_from_ext_api} -> {:ok, params_from_ext_api}  - на фронт
    _ -> {:error, unknown_ref_from_ext_api_expired} - на фронт
  end

end,

fn pid -> {:error, no_response_from_ext_api} end

)
источник

S

Serg in ErlangRus
когда ExtAPI сделает callback request в мое приложение то непонятно как это попадет в блок receive? по ref_from_ext_api полученному ранее...
источник

S

Serg in ErlangRus
Alex Bubnov
в next_fun - как я уже сказал, receive.
def get(url) do
   Stream.resource(

     #start_fun
     fn ->
       HTTPoison.get!(
          url,  %{},
          [stream_to: self(), async: :once]
       )
     end,
     #---------------------
     #next_fun

     fn %HTTPoison.AsyncResponse{id: id}=resp ->
   receive do
     %HTTPoison.AsyncStatus{id: ^id, code: code}->
       IO.inspect(code, label: "Status code: ")
       {:halt, resp}
   after
     5_000 -> raise "receive timeout"
   end,

    end_fun #todo

   )
 end
end

вот пример.  но тут синхронный ответ от внешнего апи просто передается в next_fn

а в моем случае взаимодействие с внешней системой асинхронное. то есть после start_fun я лишь получаю ref. А позже внешняя система по этому ref сделает callback request на мое приложение. То есть pid полученный в start_fn никак не связан с next_fn (
источник

ИИ

Иванов Иванов... in ErlangRus
Serg
def get(url) do
   Stream.resource(

     #start_fun
     fn ->
       HTTPoison.get!(
          url,  %{},
          [stream_to: self(), async: :once]
       )
     end,
     #---------------------
     #next_fun

     fn %HTTPoison.AsyncResponse{id: id}=resp ->
   receive do
     %HTTPoison.AsyncStatus{id: ^id, code: code}->
       IO.inspect(code, label: "Status code: ")
       {:halt, resp}
   after
     5_000 -> raise "receive timeout"
   end,

    end_fun #todo

   )
 end
end

вот пример.  но тут синхронный ответ от внешнего апи просто передается в next_fn

а в моем случае взаимодействие с внешней системой асинхронное. то есть после start_fun я лишь получаю ref. А позже внешняя система по этому ref сделает callback request на мое приложение. То есть pid полученный в start_fn никак не связан с next_fn (
для оборачивания кода можно использовать тройные апострофы
источник

AB

Alex Bubnov in ErlangRus
Serg
когда ExtAPI сделает callback request в мое приложение то непонятно как это попадет в блок receive? по ref_from_ext_api полученному ранее...
Это уже другая часть истории, с ets или процессом-регистратором, неспецифичный для эликсира
источник

PG

Pig Greenest in ErlangRus
Иванов Иванов
для оборачивания кода можно использовать тройные апострофы
Бэктики, не знаю как по русски
источник

S

Serg in ErlangRus
Иванов Иванов
для оборачивания кода можно использовать тройные апострофы
+
источник

ИИ

Иванов Иванов... in ErlangRus
Pig Greenest
Бэктики, не знаю как по русски
гравис, обратный апостоф
источник

LL

Lama Lover in ErlangRus
Serg
Добрый день

Elixir-новичкам помогают тут?


Имею на erlang+cowboy рабочее приложение подменяющее асинхронное взаимодействие синхронным:

1. принял запрос с фронт устройства/браузера X в cowboy
2. отправил http-запрос во внешнюю систему Y, получил в ответе ref
3. сохранил PID-коннекта с X и ref от Y в ETS-таблице {ref_from_y, pid_from_x}
4. через cowboy_loop handler вывешиваю соединение(=процесс X) для ожидания ответа от внешней системы Y

5. Внешняя система Y шлет в cowboy http-запрос с ref
6. В ETS по ref ищу  PID-процесса который держит коннект с устройством X
7. шлю сообщение в указанный процесс PID ! {some_msg_fromY} на фронт/устройство

Есть задача перейти на Elixir/Phoenix.

Вопрос: какой инструмент/модуль Elixir/Phonenix использовать для построения такого взаимодействия?

Почитал про Task/Agent/Job/Flow  - ни один не подходит. Все равно приходится ETS + Process.send использовать как в erlang ... В какую сторону копать?
Принимаешь запрос и делаешь GenServer.call в процесс-запрашиватель
В процессе-запрашивателе делаешь запрос в Y и ждёшь ответа
Получив ответ, отвечаешь на call

Конец
источник