Aino, an experimental HTTP framework for Elixir
blog.oestrich.org
blog.oestrich.org
I feel the same way. I'm not a fan of approaches that keep so much state on the server (LiveView and its clones). That's a disagreement I have with Phoenix's general direction.
Likewise, 'stateful' applications keep local state, and 'stateless' applications push everything off to either the client or database. They become fungible commodities- at peak load, you can quickly spin up more and shut them down after. With a 'stateful' application, you need to keep it running as long as the sessions (and maybe background jobs or any other local state) are live, unless you have some trivial means of passing that off to another machine.
Load balancing also means needing sticky sessions (i.e. once a client connects to an application server behind the load balancer, the load balancer needs to be able to keep sending the client to the same server). It's a solved problem, but needing to deal with it at all is a thing.
The web got along just fine with stateful applications for years, and things like websockets mandate a certain amount of statefulness, so there's nothing wrong with using it if you want to... OTOH you might just save yourself a lot of pain and effort if you don't. Right tools for the right jobs and all that.
I don't understand this part. What are "dead views"? I would have thought maybe they are views to which no client is connected anymore, but the rest of the paragraph seems to contradict that. What is the "current trajectory of Phoenix" that is alluded to?
A simple example
defmodule AddressParser.PlugHandler do
import Plug.Conn
require Logger
def init(options) do
Logger.info("Running #{__MODULE__} with Plug using http://0.0.0.0:8080")
options
end
def call(
%Plug.Conn{method: method, request_path: request_path, query_string: query_string} = conn,
_opts
) do
request_id = generate_request_id()
Logger.info("#{request_id} #{method} #{request_path} #{query_string}")
case handle_request(method, request_path, URI.decode_query(query_string)) do
{:ok, response} ->
Logger.info("#{request_id} sent 200 ok")
conn
|> put_resp_content_type("application/json")
|> send_resp(200, Jason.encode!(response))
{:error, status, response} ->
Logger.error("#{request_id} sent #{status} #{response}")
conn
|> put_resp_content_type("text/html")
|> send_resp(status, response)
end
end
defp handle_request("GET", "/parse", %{"address" => address}) do
{:ok, Address.parse(address)}
end
# more handlers
...
end