Calling functions on a Phoenix worker

Well, I am suprised. Why for a technology so cool, elegant and pleasant… the community is so … strange :slight_smile: I did read the docs, just overlooked the “name registration” piece. No one wrote code for me to paste. It was not my intent either. I was looking for a way to call not having a pid. As simple as that. I did explain what I meant with Phoenix “use case”, got a hint from others, solved my problem, thanked, but you keep telling some stories (the entire quote about phoenix genearting code is MADE UP) and lecturing me :slight_smile: I will think twice before I post a question next time. You guys just relax.

So then we seem to have also got your question wrong. May I apologize? It would be a pity if you left just because we talked past each other.

1 Like

No need :slight_smile: C’mon! Thank you guys for you help and I am not going to leave for sure. BTW, as an ex-Java, Scala and Clojure dev (started Java in 2002)…I must say Elixir/Phoenix rock! Hats off to all contributors.

2 Likes

Welcome here and I’m glad that you received the answer you was looking for.
Enjoy Elixir with us :slight_smile:

FYI: Supervisor.Spec has been deprecated:

So in v1.5, assuming that Foo.Worker specifies use GenServer while FooWeb.EndPoint and Foo.Repo specify use Supervisor the following should work:

def start(_type, _args) do

  children = [
    Foo.Repo,
    FooWeb.Endpoint,
    Foo.Stats
  ]

  opts = [strategy: :one_for_one, name: Foo.Supervisor]
  Supervisor.start_link(children, opts)
end

In a module-based supervisor the following approach would be typically used

defmodule Foo.Supervisor do
  use Supervisor

  def start_link(args),
    do: Supervisor.start_link(__MODULE__, args)

  def init(stash_pid) do
    children = [
      Foo.Repo,
      FooWeb.Endpoint,
      Foo.Stats
    ]

    opts = [strategy: :one_for_one, name: __MODULE__]
    Supervisor.init(children, opts)
  end
end

When you specify use GenServer in a module a child_spec/1 function is automatically added to your module which is roughly equivalent to (in truth there is more going on):

def child_spec(firstArg) do
%{
  id: __MODULE__,
  start: {__MODULE__, :start_link, [firstArg]},
  restart: :permanent,
  shutdown: 5000,
  type: :worker
}
end

The child_spec/1 function is called when just the plain module name is used in the child list. You can specify the argument

    children = [
      Foo.Repo,
      FooWeb.Endpoint,
      {Foo.Stats,"My First Argument"}
    ]

otherwise [] is assumed. The specs can also be overridden on the module level:

   use GenServer, start: {__MODULE__, :start_link, ["fixed first argument","fixed second argument"]}

Module Child Specification

use Supervisor essentially works the same way - the only difference is that :type is set to :supervisor.

Alternately the supervisor can use Supervisor.child_spec/2

    foo_spec = (Supervisor.child_spec Foo.Stats, start: {__MODULE__, :start_link, ["1st arg","2nd arg"]})
    children = [
      Foo.Repo,
      FooWeb.Endpoint,
      foo_spec
    ]

or the supervisor can just specify everything:

    foo_spec = %{
      id: Foo.Stats,
      start: {Foo.Stats, :start_link, ["1st arg","2nd arg"]},
      restart: :permanent,
      shutdown: 5000,
      type: :worker
    }

    children = [
      Foo.Repo,
      FooWeb.Endpoint,
      foo_spec
    ]

One could actually nitpick as :name isn’t an argument but simply an option - and options always occur as the last parameter and are specified as part of a keyword (list).

So

def start_link() do
  GenServer.start_link(__MODULE__, [], name: Foo)
end

is in fact

def start_link() do
  GenServer.start_link(__MODULE__, [], [{:name, Foo}])
end