0

My Genserver terminates after a little while, after sending a few http requests. I can't understand the reason:

[error] GenServer MyGenServer terminating
** (stop) exited in: Task.await(%Task{owner: #PID<0.420.0>, pid: #PID<0.1054.0>, ref: #Reference<....>}, 5000)
    ** (EXIT) time out
    (elixir) lib/task.ex:416: Task.await/2
    (elixir) lib/enum.ex:966: Enum.flat_map_list/2
    (my_app123) lib/my_genserver.ex:260: MyApp.MyGenServer.do_work/1
    (my_app123) lib/my_genserver.ex:180: MyApp.MyGenServer.handle_info/2
    (stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:683: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: :tick
State: [%{var1: "fdsafdsfd", var2: "43243242"}]

A chunk of the code:

  # it's called from handle_info

  def do_work(some_data) do
    Enum.map(some_data, fn(x) ->
      Task.async(fn ->
        case HTTPoison.post(.....) do
        # ...........

Is "Task.async" causing the timeout? But why? Yes, it can take more than 5 seconds to complete, but why does it cause an exception which then terminates GenServer? How to fix it?

About await:

If the timeout is exceeded, await will exit; however, the task will continue to run. When the calling process exits, its exit signal will terminate the task if it is not trapping exits.
Jodimoro
  • 4,355
  • 3
  • 11
  • 18

1 Answers1

3

As the documentation says, Task.await has a default timeout of 5 seconds after which it exits (terminates) the the calling process. You can increase the timeout like this:

Task.await(task, 60000) # 1 minute

and you can remove the timeout completely by passing :infinity as the timeout instead of a number:

Task.await(task, :infinity)
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • and if I only want not to throw an error? namely, it to occur silently? try ... catch inside task.await? – Jodimoro Jun 13 '17 at 07:27
  • I think you want `Task.yield/2` then, which accepts a timeout and returns `nil` if the timeout occurs instead of throwing an error and returns `{:ok, value}` on success. – Dogbert Jun 13 '17 at 07:32
  • `default timeout of 5 seconds after which it throws an error` -- where does it say "error" in the documentation? – Jodimoro Jun 13 '17 at 07:35
  • You're right, it exits, not throws an error. It's better to use `Task.yield/2` then if you want a timeout but you want to handle the timeout instead of exiting the current process. – Dogbert Jun 13 '17 at 07:40
  • but what's the difference? why better? given that I might not want to handle the timeout. And why does my code throw an error then? – Jodimoro Jun 13 '17 at 07:41
  • and also **yield** --> `Temporarily blocks the current process waiting for a task reply.` -- I don't want to block. Although, **await** blocks also, right? – Jodimoro Jun 13 '17 at 07:44
  • Your code doesn't throw an error, it exits. GenServer logs the exit as an error. If you don't want to block (therefore you don't want the return value) and you don't want to handle errors, why don't you just not call `Task.await`? The Task will run and exit on completion in the background. – Dogbert Jun 13 '17 at 07:46
  • Seems to me that you just want to use `spawn` instead of `Task.async`. If you use `Task.async` you should wait for the task to finish and handle errors and timeouts. With `spawn` you can "fire and forget" :-) – valo Jun 13 '17 at 07:47
  • `why don't you just not call Task.await? ` - my code is doing exactly this – Jodimoro Jun 13 '17 at 07:47
  • actually, I need a result because it's a GenServer and it needs a result so that it can remove an item from an list/state if it's done or continue if it's not yet. – Jodimoro Jun 13 '17 at 07:57
  • If you just want to know the status of a Task without blocking, you can use `Task.yield(task, 0)`. This will return immediately with either `{:ok, result}` if the task has finished, or `nil` if the task is still running. – Dogbert Jun 13 '17 at 09:29
  • If you need the result, you need to handle the timeout or specify `:infinity` for the timeout. – valo Jun 13 '17 at 11:31