nezzart
I’ve read on GenServer, but am not able yet to use it because not everything yet makes sense to me.
I want this:
- when a user clicks on a button, a new task begins
- a task terminates depending on some external condition, say, an external rest-api webservice has returned “terminate = true”
- if a task is already running, clicking on a button shouldn’t begin a new
- a task poll an external rest-api webservice every 30 seconds
I was adviced to use a single GenServer. My questions:
-
how can I associate a new task or its name with a user’s id? so that when he clicks on a button I can check if I need to create a new task or do nothing if there’s already one running?
-
how can I add/remove an item to MyWorker? Meaning, should I keep a list of users id?
-
if there’re no tasks, GenServer should stop. I think. Is it a wise thing to do? If so, how can I stop/run it?
-
to re-run a task every 30 seconds I need to call schedule_work() in “poll_external_service”, correct? Thus, to terminate it, depending on a response from an external web rest service, I merely don’t run schedule_work(), correct?
defmodule MyWorker do
use GenServerdef start_link do GenServer.start_link(__MODULE__, [], name: :my_app_worker) end def init(state) do schedule_work() {:ok, state} end def add_item(x) do end def remove_item(x) do end defp poll_external_service do # a request to an external web server schedule_work() end defp schedule_work() do Process.send_after(self(), :work, 30 * 1000) endend
Trending in Questions
Other Trending 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
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Marked As Solved- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
net
I may have misunderstood what you’re trying to do, but this might help.
Assuming that you only wanted to store the user ID for each ask, I used a MapSet. If you want to store additional data with the task (such as a specific URL to poll), you should use a Map (with the key being the user ID, as map keys are unique).
In
process_tasks/1we useEnum.filter/2to both call a function for each task, and to remove tasks that the external API has indicated should be terminated. Thecase ExternalAPI.poll(id) dois of course, a contrived example. What’s important is that the anonymous function given toEnum.filter/2returnsfalseif the task should be removed. (You can giveEnum.filter/2a map too, if you go that route. In that event the anonymous function should take a tuple{user_id, data}representing each key-value pair in the map.)There’s no need to stop the GenServer when there are no tasks. Erlang processes are very lightweight.
Also Liked
OvermindDL1
Yes, and it is described in the GenServer documentation.
Imagine genserver implemented this way in pseudo-code:
And so forth, but with significantly more error checking and cases and such. GenServer is just an infinite receiving loop passing the state from iteration to iteration.
net
You’re right, that is better. Instead of
Enum.filter/2you might consider just usingEnum.each/2and callingMyWorker.remove/1from the process handling the individual task if the task should be removed.Qqwy
The
MyWorkeruses the:nameoption as part of thestart_linkcall, which means that the process is registered under a global (node-wide) name. The other calls that useGenServer.callandGenServer.castuse the same name to access it later.So this means that the process will remain available after starting until your application closes, the process crashes, or you call
GenServer.stop/2from somewhere. In any case, the process will remain regardless of the connecting/disconnecting of users to your web-facing interface.Last Post!
balena
I would recommend you to have a look at the Registry module.
First, some considerations:
GenServerper user;GenServerprocess.Tackling the first part, which involves associating a user’s id with a process, start one if one is not running and keeping a list of executing processes based on the user’s name, can be done using the following construct:
Assuming the above, then now you could create another process to re-run the worker process every 30 seconds. This another process can hold a simple
Mapwhere the key is the user’s id and the value is the task. Just callMyScheduler.add_item/2when the user clicks on the button, followed byMyWorker.start_worker/2if you want to process the task immediately, otherwise, the worker will be executed 30 seconds later by the scheduler.With the above:
MyScheduler.remove_item/1for the same user ID you used inMyScheduler.add_item/2.