Phoenix: running a function on startup & general structure

Hello there!

I am a complete novice to Elixir, Phoenix and functional programming itself. I am quite overwhelmed by the whole file structure you get when starting with Phoenix. To get to know it a little better, I want to do the following:

I have a Model called Document. It holds some metadata for files that exist locally on my machine (field “filename” in the model). I also added a config value documents_path where those documents are supposedly stored. On startup (or ideally in a set interval), I want to verify whether the Documents in the database and the local files match up (does the file locally exist? If not, we should get rid of the database entry).

I have several questions now:

  1. Where do I put my function (lets assume its named verify_document_cache). Do I put it in the DocumentController?
    1.1 If not, where do I put it and how do I gain access to the Repo so I can call Repo.all, or do I create a helper for that somewhere else?
  2. Is it the “correct” way to run it from the lib/my_app.ex file as stackoverflow suggests?
    2.1 How do I “include” the DocumentController (or whereever I will implement the function)? I tried require Myapp.DocumentController or just require DocumentController but the compiler complains that they do not exist.
  3. how do I do stuff in intervals?

Thank you for your answers.

There are multiple ways to do it. One that makes sense to me is add a process which will verify_document_cache on an interval basis. Since I’d like to make sure the process is restarted when it crashes, I would add it to a supervisor and make it a GenServer (like more in line with other OTP stuff).

You’ll already find some gen_server supervised in lib/my_app.ex (like App.Repo).
You could then write a GenServer and put it in lib/document_verifier.ex:

defmodule MyApp.DocumentVerifier do
  alias MyApp.Repo
  require Logger
  use GenServer

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

  def init(_) do
    Process.send_after(self, :verify_docs, 5 * 60 * 1000) #5 min, 60 sec, 1000 millisecs
    {:ok, []}
  end

  def handle_info(:verify_docs, state) do
    verify_docs
    Process.send_after(self, :verify_docs, 5 * 60 * 1000) # reschedule job after 5min
    {:noreply, state}
  end

  defp verify_docs do
    # use stuff from Repo etc to verify your docs
  end
end
2 Likes

I recommend reading https://shift.infinite.red/beyond-10-000-lines-ba1adc17cc7b#.lvk0rjbnt as what it describes is really one of the best way to structure the program.

3 Likes

Thank you! I’ll try it out once I get home.

I did actually read it today which sparked further interest in Elixir/Phoenix :slight_smile:

1 Like

Thanks for that, was very informative.

1 Like