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
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (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.
nezzart
Thanks.
In you example In process_tasks a list of tasks is iterated over and an http request ExternalAPI.poll is sent syncronously and therefore waited for a response syncronously as well. Is that a wise thing to do? Why not create for each http request a separate thread?
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.nezzart
Should that be done via spawn? something like this:
Then how would I do filtering if all them are in different thread? Will I have to wait something for all them for finish in each iteration?
net
I would use a Task.
As I mentioned, if you go that route you may not want to use
Enum.filter/2. Instead, call theremove/1function from inside the Task process with the user ID of the task to be removed.nezzart
Also, how is an instance of MapSet stored between http requests? I mean, an http request to an html page: a user reloads a page with a button and … a list of tasks is gone? In a session or is there more idiomatic way?
net
I’m not entirely sure what you’re asking.
The MapSet is stored as the
MyWorkerGenServer’s state on the server. TheMyWorkerGenServer is a continuously running process that should be started as part of your application’s supervision tree when your application starts. You should not be starting and stopping it on demand when a user loads or reloads a page.nezzart
There’s no variable in MyWorker which stores MapSet. Where is it stored?
Will you show me a simple example of a client of MyWorker?
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.nezzart
that’s not what I asked about.