I often have a need for fast access to application-wide pieces of data. One common example would be application configuration parameters. Yes, they can be stored in the config files, and then “fetched” relatively quickly when needed but this is very inflexible and does not allow any modifications on-the-fly.
In “the other” web application framework I sometimes used a singleton class initialised from persistent storage (database table) upon first instantiation. It was fast enough and flexible in the sense that not only it served the configuration data across the whole application w/o DB round-trips or over-frequent object instantiations/collections but I also could build administrator interface where the parameters could be adjusted at will and changes would be both immediately accessible across the whole system and also persisted to the database so that server/application restart could not affect their values.
Now, what would be a “kosher” Elixir/Phoenix method of achieving similar functionality?
YEah but… no really. More like a “fast local data server”. Something that wouldn’t have to reach out in order to fetch the data and serve it to consumers. It is vaguely similar to what one might want to use e.g. Redis for but only for tiny datasets, faster on very frequent reads and more confined – no outside trips except for persisting the highly infrequent changes.
Ideally something that would not require additional dependencies, like in the example I described above. From what I read in the docs, something built around GenServer or Agent could fit the bill but maybe what I need is a common use case, for which there is already a design pattern/best practice ?
Again, for persistence I’d rather use what I already have (properly managed) anyway - the DB.
FunWithFlags works as you described. It’s backed by a DB and uses Phoenix pub/sub to update the cache (ETS) on every node when a value is modified through the UI.
The ultimate for fast reads + very infrequent writes would be persistent_term.
You can still do that easily in Elixir. Just make a GenServer that read persisted data on startup and put everything into Application’s configuration, then expose an API that read from Appication.get_env/3 and write to both Application.put_env/4 and the database.
To persist configuration in a flat file, I’d write a text file with :io_lib.format("~tp.~n", [term]), which can be read back with :file.consult(path). The file is in the format of the sys.config format, editable and more expressive than json.