How to persist Genserver despite ** (Jason.DecodeError) unexpected byte at position 0: 0x3C ('<') error?

defmodule WalletValueSupervisor do
  use Supervisor

  def start_link() do
    Supervisor.start_link(__MODULE__, name: __MODULE__)
  end

  def init(_) do
    children = [
      worker(WalletValue, [], restart: :permanent)
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end
end
defmodule WalletValue do
  use GenServer

  @tenth_of_a_second 100
  @one_second 1000

  def start_link() do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  @impl true

  def init(opts) do
    start_up()
    Process.send_after(self(), :tick, @one_second)
    {:ok, opts}
  end

  @impl true

  def handle_info(:tick, _state) do
    main()
    Process.send_after(self(), :tick, @tenth_of_a_second)
    {:noreply, :running}
  end

iex(1)> WalletValueSupervisor.start_link runs perfectly fine for a few minutes until:

14:57:25.554 [error] GenServer WalletValue terminating
** (Jason.DecodeError) unexpected byte at position 0: 0x3C ('<')
    (jason 1.2.1) lib/jason.ex:78: Jason.decode!/2
    (arbit 0.1.0) lib/Wallet.ex:15: Wallet.assets/0
    (arbit 0.1.0) lib/Wallet.ex:61: Wallet.account/0
    (arbit 0.1.0) lib/Wallet.ex:88: Wallet.reformat/0
    (arbit 0.1.0) lib/WalletValue.ex:26: WalletValue.handle_info/2
    (stdlib 3.13.2) gen_server.erl:680: :gen_server.try_dispatch/4
    (stdlib 3.13.2) gen_server.erl:756: :gen_server.handle_msg/6
    (stdlib 3.13.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Last message: :tick
State: :running

** (EXIT from #PID<0.341.0>) shell process exited with reason: shutdown

What do I need to add/modify in defmodule WalletValueSupervisor to restart GenServer WalletValue after shutdown?

It will restart after terminating, since you have set restart: :permanent. However, the state of the GenServer is going to be lost.

UPD: Forgot to mention:
There is also a “burst rate” set by default so if it fails more than 3 times in 5 sec then its parent Supervisor gives up and terminates. You can tune that rate by setting options:

:max_restarts - the maximum number of restarts allowed in a time frame. Defaults to 3.
:max_seconds - the time frame in which :max_restarts applies. Defaults to 5.

See start_link/2, init/2 and strategies

As I see you have period of rerunning your job equals to tenth of a second - that’s probably it.

But I don’t think that’s the right way to handle your issue with decoding JSON… I think it would be more appropriate to use Jason.decode (without bang!) and handle {:ok, result}/{:error, reason} tuples, so it won’t crash the process

2 Likes

Got rid of the bang, modified the code accordingly and now we’re golden. Thanks again! :slight_smile: