Skip to content
This repository has been archived by the owner on Jun 10, 2024. It is now read-only.

Distribution from browser to host #343

Open
8 tasks
KronicDeth opened this issue Oct 17, 2019 · 4 comments
Open
8 tasks

Distribution from browser to host #343

KronicDeth opened this issue Oct 17, 2019 · 4 comments

Comments

@KronicDeth
Copy link
Collaborator

To be able to support the community debugging tools, specifically Observer, we'll need to be able to expose the Lumen runtime running in a browser tab to the host. Because the host wants to connect to nodes it can find by first talking to EPMD, we will need a proxy that shows up as another node on the host, but then gets forwarded to the browser.

  • Make the distribution transport pluggable in lumen_runtime.
    This may be the same interface as net_kernel or something specific to Lumen using Rust fn similar to the time source.
    • Use @mobileoverlord's phoenix_client to connect to the HOST
      • Use wrapper around Lumen.Web.WebSocket to connect to HOST in place of websocket_client that phoenix_client uses by default.
  • A Lumen.BeamSplitter Elixir project that runs on the HOST
    • A dedicated socket, similar to how phoenix_live_reload is on a separate socket prefix from the app's default one
    • Bind a port on the host that can act as a secondary node on the host (PROXY_PORT)
    • Negotiate with EPMD so it thinks PROXY_PORT is another node.
    • Pass messages received on PROXY_PORT to the Phoenix Channel

With this setup it should be possible for :observer.start() launched from iex -S mix phx.server on HOST to then connect to the localhost:PROXY_PORT and talk to the Lumen runtime in the browser tab.

Alternatives

net_kernel on HOST

Overriding net_kernel on HOST so that it natively understand websockets, similar to how other developers have overridden net_kernel on Heroku and other restricted environments.

Raw WebSockets

Instead of going over Phoenix Channels, we could use a raw websocket. This makes it easier to talk to things that aren't Phoenix, but makes it hard to integrate with Phoenix as we couldn't use the Endpoint socket DSL.

@KronicDeth KronicDeth added the RFC label Oct 17, 2019
@KronicDeth KronicDeth added this to the ElixirConf 2019 ⥛ milestone Oct 17, 2019
@bitwalker
Copy link
Collaborator

I’m a bit confused by the hang up on EPMD, with BEAM it is possible to provide your own EPMD backend, this is often used to remove the dependency on EPMD from environments where it is not supported. This combined with a custom distribution transport should allow avoiding EPMD entirely. See epmdless as an example.

@KronicDeth
Copy link
Collaborator Author

I get you can go without EPMD, but I want to support still having EPMD so that potentially this could run in a normal host project, similar to how Phoenix Live Reload does for Phoenix project and not need to enforce going EPMDless on the entire project.

@bitwalker
Copy link
Collaborator

I'd like to understand the benefit of supporting EPMD here, at least initially. I'm not super convinced that there is anything to be gained.

We definitely can't support remote shells in non-local/non-dev settings (for the browser target), since it would absolutely overwhelm distribution, so the general case of wanting the app to use EPMD in production isn't relevant. So we're really talking specifically about getting a remote shell node to connect via a single host node, to a single client-side node. In that setting we don't have a need for EPMD, and removing it as a requirement involves less moving parts, as far as I can tell.

To give you the idea of how I see it working:

  • Start the app, this is configured to use the custom WebSocket distribution transport and a EPMD backend that is aware of the client-side node; as the client-side Lumen node is connected via WebSockets to the app. The client-side node uses a special node name that is always the same (e.g. [email protected]). The EPMD backend hosts a WebSocket server which relays messages to the client-side node.
  • Start local debug node with [email protected] EPMD_MODE=client iex -S mix --erl="-proto_dist websocket_dist -epmd_module custom_epmd" --hidden --cookie foo --name [email protected] --remsh [email protected]

The debug node is running the same EPMD backend, but configured to run as a client rather than server. It connects to the [email protected] name by connecting to the node in $EPMD_APP_NODE as a WebSocket proxy.

NOTE: The invocation of iex above wouldn't actually need all of those flags since it would already be provided as part of app configuration, it is more to illustrate what's needed.

To be clear, I'm not saying your solution isn't viable, or unacceptable, I think it is both; I'm just hoping that there is a simpler solution possible. If what I'm suggesting above isn't simpler, or if there are other reasons it isn't viable or less than ideal, that's fine, I don't see any reason why your proposal isn't viable.

@bcardarella
Copy link

Note to reassess if the WASM debug support is good enough to replace this effort

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants