Odd behavior of Task.Supervisor.async_stream_nolink

The following code hangs indefinitely:

Task.Supervisor.async_stream_nolink(
        TemporaryTaskSupervisor,
        1..1000,
        fn item ->
                IO.puts("processing item #{item}")
                raise("runtime error")
        end,
        timeout: 120_000,
        max_concurrency: 2
)
|> Stream.run()

The output is:

processing item 1
processing item 2
processing item 3
processing item 4
processing item 5
processing item 6
processing item 7
processing item 8
processing item 9
processing item 10
processing item 11
processing item 12
processing item 13
processing item 14
processing item 15
processing item 16
processing item 17
processing item 18
processing item 19
processing item 20
processing item 21

and then the process hangs.

Is this an Elixir bug or am I misunderstanding something with the use of async_stream_nolink? The docs seem to indicate that it will spawn a task for each enumerated item and collect all responses, even if the task exits (because it’s not linked to the caller), but that’s not happening - it stops going through the list after a certain number of items and is just waiting for something.

Hi @dkulchenko!

What is your Elixir and Erlang/OTP versions? Can you provide a full example that reproduces the error?

I did this. I put the below in a file named foo.exs:

Task.Supervisor.start_link(name: TemporaryTaskSupervisor)

Task.Supervisor.async_stream_nolink(
        TemporaryTaskSupervisor,
        1..1000,
        fn item ->
                IO.puts("processing item #{item}")
                raise("runtime error")
        end,
        timeout: 120_000,
        max_concurrency: 2
)
|> Stream.run()

And then I did elixir foo.exs.

I could see locally that it processed all 1000 elements. I am on Erlang/OTP 22+ and Elixir v1.9.4.

4 Likes

You’re totally right, apologies, I should’ve tested that in a non-application environment - it works when run as an elixir script but didn’t work when I ran it under mix run test.exs within my app, which was really weird.

The issue turned out to be in the Sentry logger backend (https://github.com/getsentry/sentry-elixir/issues/371), it seems a series of logger messages that fail to be delivered will block any process that attempts to use the Logger, including logging task crashes like in the example script.

1 Like