Fl4m3Ph03n1x
GenServer pass file path
Background
I have an OTP application that reads a CSV file and puts it into memory. After following some advice from this community I went with the following approach:
- My app file has 2 modules:
PopulatorandReader.Populatoropens the file and indexes its contents into a persistent_term table, whileReaderis a client that queries said table. Populatoris a Genserver, that starts with stateinitializing. Once it loads the file into memory its state evolves to:readyor:errordepending on the outcome.- Before making a request, the
Readerchecks thePopulator’s state. If its:readyit queries the memory table, otherwise refuses the request.
Best practices
Now, the issue here is initialization. As a Genserver, my Populator has the file’s path hardcoded. This app is a library with, so following the good guidelines of libraries states that this is a terrible idea.
I could put the file path into a config file inside a config folder, but the directives for good libraries discourage this. They instead encourage me to have a function in the Populator called populate_memory (for lack of a better name) that upon receiving a file name, opens the file and fills the table.
Problem
But the problem with this approach is that if I do it that way, then the projects that use the library will have to deal with Engine failure on startup, and the code will endup looking like this:
defmodule FootbalInterface.Application do
@moduledoc false
use Application
alias FootbalEngine
require Logger
def start(_type, _args) do
children = []
opts = [strategy: :one_for_one, name: FootbalInterface.Supervisor]
case FootbalEngine.new(file_path) do
{:ok, :indexation_successful} ->
Logger.info("""
Application launched successfully.
Waiting for requests.
""")
Supervisor.start_link(children, opts)
{:ok, :partial_indexation_successful, fails} ->
Logger.warn("""
Application launched with errors. Check the CSV file for:
#{inspect fails}
Waiting for requests.
""")
Supervisor.start_link(children, opts)
{:error, :no_valid_data_to_save} ->
Logger.error("""
Failed to launch application. CSV file has no valid data.
Shutting down.
""")
{:error, :invalid_csv}
{:error, reason} ->
Logger.error("""
Failed to launch application. An unknown error occurred:
#{inspect reason}
Shutting down.
""")
{:error, reason}
end
end
end
Which has also been heavily discouraged by the community in previous posts.
Question
So, how do I follow best practices for libraries and still follow the community recommendations for my use case?
Marked As Solved
LostKobrakai
It would be a library without own supervision tree. It just has module(s), which can be started by other applications. There’s therefore no need for an application.ex in your library.
I’m not sure what supervisor you’d need in your library if FootbalEngine is a genserver.
Also Liked
LostKobrakai
If that’s part of you library users’ supervision tree your library itself does not hardcode anything. And yeah, all my code examples would live in the users MyApp.Application, not your library. I missed specifying that.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









