barrelltechgh

barrelltechgh

Capturing timeouts with FLAME

I’m using FLAME to run some code that has a tendency to fail (external libraries that are out of my control). When FLAME works, it works great; when it fails, it will normally work if I just rerun it.

I’m having two main issues:

  1. Sometimes the boot time can take several minutes for a machine. I would say 1/2 of the time it’s less than 1 minute, 1/4 of the time it’s between 1 and 2 minutes, and 1/4 of the time between 2 and 10 minutes (I think 8 minutes is the longest I’ve seen it take).
  2. If the process fails, it fails in a bunch of spectacular and varied ways. OOM, process crashed, process hangs, infinite loops… fun stuff.

What I’ve found works the best is to wrap it in a bunch of try catch rescue blocks, give the FLAME pool a long boot_timeout, and give the FLAME pool a standard normal timeout.

However, when FLAME times out the process, I get this message:

** (EXIT from #PID<0.1418.0>) shell process exited with reason: killed

And no response back to my parent caller of the process.

The only way I know how to resolve this is to wrap it in my own Task and give it a timeout and handle that, but this does not give me the ability to give it extra time for a boot timeout.

This is all the control and error logic I have wrapped around a single call, where really all I care about is reliably returning an {:ok, val} or {:error, reason} tuple:

  @timeout :timer.seconds(60)

  def timeout(), do: @timeout

  # returns {:ok, {spans, words}} or {:error, reason}
  def spanwords(text, language) do
    lang = Lang.find(language)
    pool = to_pool(lang["stanza"])

    FLAME.call(pool, fn ->
      try do
        Producer.spanwords(text, lang["xxx"])
      catch
        :exit, reason -> {:error, {:exit, reason, :runner}}
      end
    end)
  catch
    :exit, reason -> {:error, {:exit, reason, :caller}}
  end

  def spanwords(text, language, retries) do
    res = spanwords_async(text, language)
    base_case = is_nil(retries) || retries < 1

    if spanwords_success?(res) || base_case do
      res
    else
      spanwords(text, language, retries - 1)
    end
  end

  def spanwords_async(text, language) do
    task =
      Task.Supervisor.async_nolink(Gambit.TaskSupervisor, fn ->
        spanwords(text, language)
      end)

    Task.await(task, @timeout)
  rescue
    error -> {:error, error}
  catch
    :exit, {:timeout, _} -> {:error, :timeout}
    :exit, reason -> {:error, {:exit, reason, :task}}
  end

I guess I’m really asking two questions:

  1. Is there a more sophisticated way to capture a timeout from a process? I want FLAME to handle the timeout to properly account for boot times, but still be able to capture that as an {:error, :timeout} tuple

  2. Error handling is still very murky for me in Elixir. Is there a more straightforward way to just so “no matter what return either an {:ok, val} or {:error, reason} tuple” (or a list thereof) instead of various different catches and rescues and Task wrapping etc?

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42842 311
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41454 115
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53578 245
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52238 488
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "eq...
New
nobody
Hi! In PHP: $SERVER['SERVERADDR'] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47849 226
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement