samuelventura

samuelventura

How to keep the Code.eval_string environment on async execution

What is the proper way to evaluate a string and get a stack trace that honors the provided file: script.exs environment across all the code defined in that script regardless of whether it is executed in the current process or deferred to an async task?

The first two samples refer to the provided file: script.exs on the stack trace and the last one loses it.

Sample 1 keeps the reference to script.exs in its stacktrace

iex(1)> Code.eval_string("""
try do
  raise "RAISE"
rescue
  e -> {e, __STACKTRACE__}
end
""", [], file: "script.exs")

{{%RuntimeError{message: "RAISE"},
[
  {:elixir_eval, :__FILE__, 1, [file: ~c"script.exs", line: 2]},
  {:elixir, :eval_external_handler, 3,
   [file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
   ...
]}, []}

Sample 2 keeps the reference to script.exs in its stacktrace

iex(2)> Code.eval_string("""
fun = fn -> raise "RAISE" end
try do
  fun.()
rescue
  e -> {e, __STACKTRACE__}
end
""", [], file: "script.exs") 
{{%RuntimeError{message: "RAISE"},
[
  {:elixir_eval, :__FILE__, 1, [file: ~c"script.exs", line: 1]},
  {:elixir, :eval_external_handler, 3,
   [file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
  ...
]}, [fun: #Function<43.81571850/0 in :erl_eval.expr/6>]}

Sample 3 loses the reference to script.exs in its stacktrace

iex(3)> Code.eval_string("""
fun = fn -> raise "RAISE" end
Task.async(fn -> 
  try do
    fun.()
  rescue
    e -> {e, __STACKTRACE__}
  end
end) |> Task.await(:infinity)
""", [], file: "script.exs")
{{%RuntimeError{message: "RAISE"},
[
  {:elixir, :eval_external_handler, 3,
   [file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
  {:erl_eval, :do_apply, 7, [file: ~c"erl_eval.erl", line: 919]},
  {:erl_eval, :try_clauses, 10, [file: ~c"erl_eval.erl", line: 1233]},
  {Task.Supervised, :invoke_mfa, 2,
   [file: ~c"lib/task/supervised.ex", line: 101]}
]}, [fun: #Function<43.81571850/0 in :erl_eval.expr/6>]}

Need this to implement scripting with accurate tracing of unhandled exceptions in async code.

Things looking into at the moment:

  1. Process.info(self(), :current_stacktrace)
  2. Last call optimisation

Most Liked

samuelventura

samuelventura

You mean like sample below? Apparently the reference to script.exs is lost as well.

iex(4)> Code.eval_string(
  """
  fun = fn ->
    raise "RAISE"
    List.flatten([])
  end

  Task.async(fn ->
    try do
      fun.()
    rescue
      e -> {e, __STACKTRACE__}
    end
  end) |> Task.await(:infinity)
  """,
  [],
  file: "script.exs"
)

{{%RuntimeError{message: "RAISE"},
[
  {:elixir, :eval_external_handler, 3,
   [file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
  {:erl_eval, :do_apply, 7, [file: ~c"erl_eval.erl", line: 919]},
  {:erl_eval, :exprs, 6, [file: ~c"erl_eval.erl", line: 271]},
  {:erl_eval, :try_clauses, 10, [file: ~c"erl_eval.erl", line: 1233]},
  {Task.Supervised, :invoke_mfa, 2,
   [file: ~c"lib/task/supervised.ex", line: 101]}
]}, [fun: #Function<43.81571850/0 in :erl_eval.expr/6>]}
josevalim

josevalim

Creator of Elixir

Oh, it works on Erlang AST rather than BEAM. :smiley: you can find it on erl_eval.

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
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

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
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

We're in Beta

About us Mission Statement