processes.tex 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. \section{Erlang Processes}
  2. \subsection{Reduced Latency}
  3. The secret to reducing latency is simple. We try to deliver rendered HTML
  4. as soon as possible and render JavaScript only when WebSocket initialization is complete.
  5. It takes three steps and three Erlang processes for doing that.
  6. \includeimage{images/page-lifetime.png}{Page Lifetime}
  7. \paragraph{}
  8. N2O request lifetime begins with the start of HTTP process serving the first HTML page.
  9. After that it dies and spawns Transition process.
  10. Then the browser initiates WebSocket connections to the similar URL endpoint.
  11. N2O creates persistent WebSocket process and the Transition process dies.
  12. \paragraph{}
  13. Your page could also spawn processes with {\bf wf:async}.
  14. These are persistent processes that act like regular Erlang processes.
  15. This is a usual approach to organize non-blocking UI for file uploads
  16. and other time consuming operations.
  17. \newpage
  18. \subsection{Page Serving Process}
  19. This processes are applicable only to the case when you serving not static HTML,
  20. but dynamically rendered pages with NITRO, DTL or ET template engines.
  21. The very first HTTP handler only renders HTML. During page initialization
  22. function Module:{\bf main/0} is called. This function should return raw HTML or
  23. NITRO elements that could be rendered into raw HTML. All created on the way
  24. JavaScript actions are stored in the transition process.
  25. \vspace{1\baselineskip}
  26. \begin{lstlisting}
  27. main() -> #dtl { file = "login",
  28. app = review,
  29. bindings = [ { body,
  30. #button { id = send,
  31. postback = chat } } ] }.
  32. \end{lstlisting}
  33. \vspace{1\baselineskip}
  34. \paragraph{}
  35. HTTP handler will die immediately after returning HTML. Transition process
  36. stores actions and waits for a request from a WebSocket handler.
  37. \subsection{Transition Process}
  38. Right after receiving HTML the browser initiates WebSocket connection
  39. thus starting WebSocket handler on the server. After responding with
  40. JavaScript actions the Transition process dies and the only process left
  41. running is WebSocket handler. At this point initialization phase is complete.
  42. \vspace{1\baselineskip}
  43. \begin{lstlisting}
  44. transition(Actions) ->
  45. receive {'N2O',Pid} -> Pid ! Actions end.
  46. \end{lstlisting}
  47. \vspace{1\baselineskip}
  48. Transition process is only applicable to dynamically rendered pages
  49. served by {\bf n2o\_document} endpoint. You never deal with it manually.
  50. \subsection{Events Process}
  51. After that all client/server communication is performed over
  52. WebSocket channel. All events coming from the browser are
  53. handled by N2O, which renders elements to HTML and actions to
  54. JavaScript. Each user at any time has only one WebSocket process
  55. per connection.
  56. \vspace{1\baselineskip}
  57. \begin{lstlisting}
  58. event(init) -> wf:reg(room);
  59. event(chat) -> #insert_top(history,#span{body="message"}),
  60. wf:flush(room).
  61. \end{lstlisting}
  62. \vspace{1\baselineskip}
  63. This code will register all WebSocket processes under the same
  64. topic in pubsub and broadcast history changing to all registered
  65. process in the system under the same topic using {\bf \#flush}
  66. NITRO protocol message.
  67. \paragraph{}
  68. During page initialization before Module:{\bf event(init)},
  69. Module:{\bf main/0} is called to render initial postbacks for
  70. elements. So you can share the same code to use SPA or DSL/DTL approach.
  71. \subsection{Async Processes}
  72. These are user processes that were created with {\bf wf:async} invocation.
  73. This processes was very useful to organize persistent stateful connection
  74. for legacy async technology like COMET for XHR channel. If you have problem with
  75. proxying WebSocket stream you can easily use XHR fallback that is
  76. provided by {\bf xhr.js} N2O companion library.
  77. Async processes are optional and only needed when you have a UI event taking too much
  78. time to be processed, like gigabyte file uploads. You can create
  79. multiple async processes per user. Starting from N2O 2.9 all async
  80. processes are being created as {\bf gen\_server} under
  81. {\bf n2o\_sup} supervision tree.
  82. \vspace{1\baselineskip}
  83. \begin{lstlisting}
  84. event(init) -> wf:reg(room),
  85. wf:async("looper", fun async/1);
  86. async(init) -> ok;
  87. aynsc(Chat) -> io:format("Chat: ~p~n",[Chat]).
  88. \end{lstlisting}
  89. \vspace{1\baselineskip}
  90. \newpage
  91. \subsection{SPA Mode}
  92. In SPA mode N2O can serve no HTML at all. N2O elements are
  93. bound during initialization handshake and thus can be used
  94. regularly as in DSL mode.
  95. \paragraph{}
  96. In the example provided in n2o/samples you can find two different
  97. front end to the same {\bf review} application which consist of
  98. two page modules {\bf index} and {\bf login}. You can access this application
  99. involving no HTML rendering by using static file serving that could be
  100. switched to direct nginx serving in production.
  101. \vspace{1\baselineskip}
  102. \begin{lstlisting}
  103. open http://localhost:8000/static/app/login.htm
  104. \end{lstlisting}
  105. \vspace{1\baselineskip}
  106. Or you can see DTL rendered HTML pages which resides at following address:
  107. \vspace{1\baselineskip}
  108. \begin{lstlisting}
  109. open http://localhost:8000/login.htm
  110. \end{lstlisting}
  111. \vspace{1\baselineskip}