bake-bake-bake / bakeware

Compile Elixir applications into single, easily distributed executable binaries
Other
1.43k stars 45 forks source link

How to call to running agent in production? #111

Open johns10 opened 3 years ago

johns10 commented 3 years ago

I know that using a dev build, I can call in to a running application with binary_name rpc "function". Once I move to production, I don't understand how to call the running application. Any tips?

johns10 commented 3 years ago

I figured this out. Basically I just copied Bakeware.Script and then added my genserver to the child list:

defmodule ElixtronAgent.Application do
  use Application

  def start(_type, _args) do
    children = [
      %{id: Task, restart: :temporary, start: {Task, :start_link, [&__MODULE__.main/0]}},
      ElixtronAgent.Server
    ]

    opts = [strategy: :one_for_all, name: __MODULE__.Supervisor]
    Supervisor.start_link(children, opts)
  end

  def parse_args(args) do
    {opts, word, _} =
      args
      |> OptionParser.parse(switches: [upcase: :open_browser])

    opts
  end

  def do_stuff(opts) do
    IO.inspect(opts)
    maybe_open_browser(opts[:open_browser])

    :ok
  end

  defp maybe_open_browser(nil), do: nil
  defp maybe_open_browser(_) do
    IO.puts("maybe_open_browser")
    ElixtronAgent.Server.open_browser()
  end

  def main() do
    get_argc!()
    |> get_args()
    |> parse_args()
    |> do_stuff()
    |> result_to_halt()
    |> :erlang.halt()
  catch
    error, reason ->
      IO.warn(
        "Caught exception in #{__MODULE__}.main/1: #{inspect(error)} => #{
          inspect(reason, pretty: true)
        }",
        __STACKTRACE__
      )

      :erlang.halt(1)
  end

  def get_argc!() do
    ...same
  end

  def get_args(argc) do
    ...same
  end

  def result_to_halt(result) do
    ...same

  end

end
johns10 commented 3 years ago

So, I've attached my own genserver to the application, and I'm running into a couple problems:

  1. Only handle_call seems to work. Not sure why, and haven't independently tested outside of the bakeware app, so might be spurrious.
  2. The genserver seems to restart on every call (I have a log message every time it starts, it throws every time I call the application).

Any ideas on these two issues?

johns10 commented 3 years ago

I think I may be calling the agent incorrectly. I've made this work with the dev version, because I can start it, and then send it rpc calls. I'm pretty sure that what I'm doing wrong is starting the agent every time. I don't actually know how to run it in production and then make RPC calls to it.

johns10 commented 3 years ago

@fhunleth @jjcarstens,

I got this working for an elixir talk I'll be giving tomorrow for ElixirToronto (https://www.meetup.com/TorontoElixir/events/278237262/). Feel free to join if you like.

Basically the goal is to use Elixtron as a background desktop application that accepts commands over a custom protocol (elixtron://Elixtron.open_browser()) that can be called directly from the browser. Those links can be authored by the live view, rendered on the page, and then calls are made directly to the assembled bakeware binary.

I put up a repo for my implementation here: https://github.com/johns10/elixtron, and here: https://github.com/johns10/elixtron_desktop

I got it pretty far in dev mode. I'd be interested in your feedback about how to tighten this up and deploy in production. I have some theories on the readme.

This is a fantastic library. I'm really happy with this implementation, and I'm hoping to ultimately replace my electron implementation of browser automation with it, and even to ship a self-contained desktop version of my liveview app that requires no internet connection.

Hoping to use it more in the future!

Regards, John Davenport

fhunleth commented 3 years ago

@johns10 That's awesome! Thanks for letting us know. I signed up for the meetup. I'm not sure if I'll be able to make it yet, but I'll try!