Потоковая передача данных с использованием streamcontent_from_pid в Yaws/Erlang

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

вот пример из рыскания (я немного изменил):

out(A) ->
    %% Create a random number
    {_A1, A2, A3} = now(),
    random:seed(erlang:phash(node(), 1),
                erlang:phash(A2, A3),
                A3),
    Sz = random:uniform(1),

    Pid = spawn(fun() ->
                        %% Read random junk
                        S="Hello World",
                        P = open_port({spawn, S}, [binary,stream, eof]),
                        rec_loop(A#arg.clisock, P)
                end),

    [{header, {content_length, Sz}},
     {streamcontent_from_pid, "text/html; charset=utf-8", Pid}].


rec_loop(Sock, P) ->
    receive
        {discard, YawsPid} ->
            yaws_api:stream_process_end(Sock, YawsPid);
        {ok, YawsPid} ->
            rec_loop(Sock, YawsPid, P)
    end,
    port_close(P),
    exit(normal).

rec_loop(Sock, YawsPid, P) ->
    receive
        {P, {data, BinData}} ->
            yaws_api:stream_process_deliver(Sock, BinData),
            rec_loop(Sock, YawsPid, P);
        {P, eof} ->
            yaws_api:stream_process_end(Sock, YawsPid)
    end.

Что мне нужно, так это преобразовать приведенный выше сценарий в такой, который можно комбинировать со следующим.

mysql:start_link(p1, "127.0.0.1", "root", "azzkikr", "mydb"),
                {data, Results}  = mysql:fetch(p1, "SELECT*FROM messages WHERE id > " ++ LASTID),
                {mysql_result, FieldNames, FieldValues, NoneA, NoneB} = Results,
                parse_data(FieldValues, [], [], [], [], [])

Где parse_data(FieldValues, [], [], [], [], []) возвращает строку записи в формате JSON. Комбинированный этот скрипт должен постоянно проверять наличие новой записи в базе данных, и если есть, он должен извлекаться, как и комета.

Спасибо, пусть все попадут в рай!


person Community    schedule 03.06.2016    source источник
comment
Хотели бы вы запросить базу данных после получения запроса через комету или, скорее, запросить базу данных в цикле и ответить через комету, как только появятся необходимые данные?   -  person Greg    schedule 04.06.2016
comment
Я бы хотел запросить базу данных в цикле и ответить через комету, как только появятся необходимые данные.   -  person    schedule 04.06.2016


Ответы (1)


Как объясняет этот ответ, иногда вам нужно запустить процесс, независимый от каких-либо входящих HTTP-запросов. В вашем случае вы можете использовать форму публикации/подписки:

  • Издатель: при запуске вашего узла Erlang запустите какой-либо клиентский процесс базы данных или пул таких процессов, выполняющий ваш запрос и работающий независимо от Yaws.
  • Подписчик: когда Yaws получает HTTP-запрос и отправляет его вашему коду, ваш код подписывается на издателя. Когда издатель отправляет данные подписчику, подписчик передает их обратно HTTP-клиенту.

Детализация полного решения здесь нецелесообразна, но общие шаги таковы:

  • Когда клиентские процессы вашей базы данных запускаются, они регистрируются в группе pg2 или в чем-то подобном. Используйте что-то вроде poolboy вместо создания собственных пулов процессов, поскольку они известно сложно, чтобы сделать это правильно. Каждый клиент базы данных может быть экземпляром gen_server, выполняющего запрос, получающего результаты из базы данных, а также обработка звонков с запросами на подписку.
  • Когда ваш код Yaws получает запрос, он ищет процесс публикации клиента базы данных и подписывается на него. Подписки требуют вызова функции в клиентском модуле базы данных, который, в свою очередь, использует gen_server:call/2,3 для связи с фактическим процессом gen_server издателя. Подписчик использует потоковые возможности Yaws (или SSE или WebSocket), чтобы завершить соединение с HTTP-клиентом и отправить ему все необходимые заголовки ответов.
  • Издатель сохраняет идентификатор процесса подписчика, а также устанавливает монитор на подписчике, чтобы он мог очистить подписку, если подписчик неожиданно умрет или выйдет.
  • Издатель использует ссылку на монитор в качестве уникального идентификатора в своих сообщениях, которым он отправляет этого подписчика, поэтому функция подписки возвращает эту ссылку подписчику. Подписчик использует ссылку для сопоставления входящих сообщений от издателя.
  • Когда издатель получает новые результаты запроса из базы данных, он отправляет данные каждому из своих подписчиков. Это можно сделать с помощью обычных сообщений Erlang.
  • Подписчик использует потоковые функции Yaws (или SSE или WebSocket функции) для отправки результатов запроса HTTP-клиенту.
  • Когда HTTP-клиент отключается, подписчик вызывает другую функцию издателя, чтобы отказаться от подписки.
person Steve Vinoski    schedule 05.06.2016