# How to interrupt async tasks?

**URL:** <https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745>\
**Category:** General Usage\
**Created:** [March 11, 2022, 12:00pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745 "2022-03-11T12:00:09Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![melonedo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/melonedo/32/15503_2.png) [@melonedo](https://discourse.julialang.org/u/melonedo)\
**Post date:** [March 11, 2022, 12:00pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/1 "2022-03-11T12:00:09Z")

</div>

Suppose I have a few tasks synchronized by `@sync` and `@async` as show below:

```julia
running = true
function task()
    i = 0
    while running
        println(i+=1)
        sleep(1)
    end
end

@sync begin
    @async task()
    @async task()
end

```

How can I catch an `InterruptException` and set `running=false` to gracefully shutdown the tasks? Currently Julia will crash immediately:

```nohighlight
⋊> ~/code julia async-interrupt.jl 19:58:321
1
2
2
^C
signal (2): Interrupt
in expression starting at /home/ubuntu/code/async-interrupt.jl:14
epoll_wait at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
uv__io_poll at /workspace/srcdir/libuv/src/unix/epoll.c:240
uv_run at /workspace/srcdir/libuv/src/unix/core.c:383
jl_task_get_next at /buildworker/worker/package_linux64/build/src/partr.c:481
poptask at ./task.jl:827
wait at ./task.jl:836
wait at ./condition.jl:123
_trywait at ./asyncevent.jl:118
wait at ./asyncevent.jl:136 [inlined]
sleep at ./asyncevent.jl:221
task at /home/ubuntu/code/async-interrupt.jl:7
#2 at ./task.jl:423
unknown function (ip: 0x7fd6b2142fdf)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1788 [inlined]
start_task at /buildworker/worker/package_linux64/build/src/task.c:877
unknown function (ip: (nil))
Allocations: 2723 (Pool: 2712; Big: 11); GC: 0

```

[Issue #35524](https://github.com/JuliaLang/julia/issues/35524) may be related.

---

<div class="post-metadata">

**Author:** ![lawless-m](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lawless-m/32/30869_2.png) [@lawless-m](https://discourse.julialang.org/u/lawless-m)\
**Post date:** [March 11, 2022, 12:37pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/2 "2022-03-11T12:37:53Z")

</div>

You can turn off Ctrl-C

[https://docs.julialang.org/en/v1/base/c/#Base.disable\_sigint](https://docs.julialang.org/en/v1/base/c/#Base.disable_sigint)

```julia
julia> function job()
    try
        sleep(50)
    catch
        println("woked")
    end
end

julia> try
    disable_sigint() do
        @sync for i in 1:100
            @async job()
        end
    end
catch
    println("ctrl-c")
end

# code is now running
# first ctrl-c
woked
# second ctrl-c
ctrl-c

julia>

```

I leave doing everything in the right order as an exercise for the reader 🙂

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 11, 2022, 12:50pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/3 "2022-03-11T12:50:13Z")

</div>

`@async` returns a `Task` - you can interact with that, though note that interrupting running tasks from a different tasks is generally not a good idea. It’s usually better to write the tasks in a way that they check some condition from time to time to make sure they can shut down gracefully or have some waitable object that you can `close`.

EDIT: for some more context:

> [@Stop/terminate a (sub)task started with @async](https://discourse.julialang.org/t/stop-terminate-a-sub-task-started-with-async/32193):
>
> Hello, I search a bit here and on the web and found out that obviously there is no “official” way to terminate a started task in julia yet. However, throw an Interruption error seems to work as a workaround for now. But now I would like to do it from within a function. Here is the example. The stating case is working but the stopping case is not. function switch\_timer(switch) if switch global t = @async while true sleep(1) end else @eval :(Base.throwto(t, InterruptException())) en…

---

<div class="post-metadata">

**Author:** ![melonedo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/melonedo/32/15503_2.png) [@melonedo](https://discourse.julialang.org/u/melonedo)\
**Post date:** [March 11, 2022, 1:46pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/4 "2022-03-11T13:46:56Z")

</div>

Thank you! But the problem is that Julia immediately crashes after receiving the interrupt, leaving no chance of executing any code.

---

<div class="post-metadata">

**Author:** ![lawless-m](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lawless-m/32/30869_2.png) [@lawless-m](https://discourse.julialang.org/u/lawless-m)\
**Post date:** [March 11, 2022, 1:48pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/5 "2022-03-11T13:48:06Z")

</div>

> [@lawless-m](#):
>
> `disable_sigint()`

prevents such events, I tired my code before I posted it

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 11, 2022, 1:48pm UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/6 "2022-03-11T13:48:17Z")

</div>

You can then `try ... catch InterruptException ... end` to handle that case - though be aware that this is pretty finicky, as it’s not really defined where exactly you’ll get that.

---

<div class="post-metadata">

**Author:** ![melonedo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/melonedo/32/15503_2.png) [@melonedo](https://discourse.julialang.org/u/melonedo)\
**Post date:** [March 27, 2022, 7:10am UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/7 "2022-03-27T07:10:22Z")

</div>

Oops I found the solution. It is because julia [exists immediately after receiving a SIGINT by default when running a script](https://docs.julialang.org/en/v1/base/c/#Base.exit_on_sigint). We can disable that by `Base.exit_on_sigint(false)`:

```julia
running = true
function task()
    try
        i = 0
        while running
            println(i+=1)
            sleep(1)
        end
        println("Task is stopped")
    catch err
        global running = false
        @error "Task is interrupted" exception = (err, catch_backtrace())
    end
end

Base.exit_on_sigint(false)
@sync begin
    @async task()
    @async task()
end
println("Program exited")

```

Now the code will exit gracefully after `ctrl+c`:

```nohighlight
 ~/julia  ./julia async-interupt.jl
1
1
^C┌ Error: Task is interrupted
│ exception =
│ InterruptException:
│ Stacktrace:
│ [1] poptask(W::Base.InvasiveLinkedListSynchronized{Task})
│ @ Base ./task.jl:935
│ [2] wait()
│ @ Base ./task.jl:944
│ [3] wait(c::Base.GenericCondition{Base.Threads.SpinLock})
│ @ Base ./condition.jl:124
│ [4] _trywait(t::Timer)
│ @ Base ./asyncevent.jl:129
│ [5] wait
│ @ ./asyncevent.jl:147 [inlined]
│ [6] sleep(sec::Int64)
│ @ Base ./asyncevent.jl:232
│ [7] task()
│ @ Main ~/julia/async-interupt.jl:7
│ [8] (::var"#2#4")()
│ @ Main ./task.jl:490
└ @ Main ~/julia/async-interupt.jl:11
Task is stopped
Program exited

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 27, 2022, 11:26am UTC](https://discourse.julialang.org/t/how-to-interrupt-async-tasks/77745/8 "2022-03-27T11:26:53Z")

</div>

This is only the behavior if nothing else catches that on the main task. The ambiguity lies in who ultimately receives the SIGINT, which in this case ends up being the main task since you throw a new error in the inner task, which gets rethrown to the `@sync` task. If you have

```julia
try
@sync begin
    @async task()
    @async task()
end
catch err
    # ...
end

```

It won’t just exit by default, even with `exit_on_sigint(true)`.
