Manzanit0
Hi all!
Some time ago I started to work on an application and I designed one of it’s workers with a start_link/0 such as this:
def start_link do
Logger.info("Starting worker")
status = @my_service.get_api_response!()
Agent.start_link(fn -> status end, name: __MODULE__)
end
I wasn’t too worried because the business logic didn’t have any side-effects apart from that start_link and the workaround I found was to simply run mix test witht the --no-start flag while starting up all the necessary applicaitions in the test_helper.ex.
The issue I’ve encountered is that when trying to adopt Phoenix now, it’s no longer convenient to run mix start --no-start, so reality kinda called back and made me deal with the real issue: How would I design an Agent/Genserver which needs to pull its initial status from an external HTTP API?
Trending in Questions
Hey guys,
I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly
Do you guys have any suggestions what is the best prac...
New
Hello!
Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app.
I creat...
New
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
Anyone here using Honeybadger?
My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of
Bandit.HTTPError...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
There are three potential reasons for members of this forum to have a look at https://vutuv.de
You are tired or annoyed of LinkedIn.
Yo...
New
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
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
kokolegorille
I would do this with a GenServer (I do not use Agent). Not in start_link, but in the init function…
There is even a handle_continue to avoid blocking when initialization is long.
Manzanit0
How would you test that? When I run
mix testthe Supervisor spins up all its children, including that one and all modules mocked withMoxare loaded.That means that
@my_service.get_api_response!()is invoked before being able to configure the mocks in the tests.I get errors similar to this:
kokolegorille
Sorry, I am not using Mox and cannot help You on this one.
peerreynders
Following dependency rejection you would design the system to obtain the initial state before even attempting to start the
GenServer- then there is no dependency that needs to be mocked out because the initial state is handed in as a plain value.Manzanit0
That’s what I thought initially – pass it throuh, and the Supervisors’ callback would look like this:
The issue is that it looks like
mixfirst spins up the Application, then runs thetest_helper.exsand lastly the tests. That means that since the mocks are set in thetest_helper.exs, it doesn’t matter what I inject to the worker in the Supervisor callback, it will always be a mock whoseget_api_response!/0function doesn’t have an expectation set.I think one solution could be to give it always an empty state as an initial state, I would however need to be able to tell the supervisor to feed it with a different state on restart, because I can’t afford to feed it an empty state every time it crashes. Is that somehow possible?
LostKobrakai
How about just not testing the genserver started by your supervision tree, but starting up additional ones with custom configuration just for your tests:
peerreynders
--no-startfixes thatSo
mix testwithout--no-startruns integration tests whilemix test --no-startonly runs the fast isolated tests.al2o3cr
The usual idiom would be to have another process, external to the worker, that holds onto that state and then supplies it to the worker when requested (maybe in the worker’s
handle_continue?)One possible sequence of events would look like:
supervisor boots the “state fetcher/holder” process
fetcher/holder boots up
(optional) if in production, the fetcher/holder can make the
get_api_responsecall fromhandle_continue. Otherwise, that call is deferred until the worker needs the data.supervisor starts the worker process
worker process makes a blocking
callfrom itshandle_continueto the holder process to get the statein production, that call returns promptly once
get_api_responsehas completedin test, that call would block (maybe with
receive?) waiting for the go-ahead from the test setup codeif the worker process crashes, the fetcher/holder can supply the already-loaded state to it when it restarts
Manzanit0
That sounds like a fine solution. How would you code the logical branches around being in production or in test? I know using
Mix.env/0isn’t an option, since that isn’t available in production, and having an environment variable which holds the values:productionor:testseems like a workaround. What’s idiomatic way of dealing with that?danj
Two things come to mind:
Unless you want the whole application to fail at startup if the initial state request fails, issue an Agent.cast after the start_link to initialize the Agent. Let the cast handler do the init. Since that cast will be first in the message queue, nothing will get to the Agent before it’s initialized. Also, in the init, you can use an Application env to control if it pulls that initial state. While you can’t use Mix.env, you can use a
configthat’s dependent on the Mix.env that’s set up at compile/release.