bevy/crates
James Liu 54a1e51623 TaskPool Panic Handling (#6443)
# Objective
Right now, the `TaskPool` implementation allows panics to permanently kill worker threads upon panicking. This is currently non-recoverable without using a `std::panic::catch_unwind` in every scheduled task. This is poor ergonomics and even poorer developer experience. This is exacerbated by #2250 as these threads are global and cannot be replaced after initialization.

Removes the need for temporary fixes like #4998. Fixes #4996. Fixes #6081. Fixes #5285. Fixes #5054. Supersedes #2307.

## Solution

The current solution is to wrap `Executor::run` in `TaskPool` with a `catch_unwind`, and discarding the potential panic. This was taken straight from [smol](404c7bcc0a/src/spawn.rs (L44))'s current implementation. ~~However, this is not entirely ideal as:~~
 
 - ~~the signaled to the awaiting task. We would need to change `Task<T>` to use `async_task::FallibleTask` internally, and even then it doesn't signal *why* it panicked, just that it did.~~ (See below).
 - ~~no error is logged of any kind~~ (See below)
 - ~~it's unclear if it drops other tasks in the executor~~ (it does not)
 - ~~This allows the ECS parallel executor to keep chugging even though a system's task has been dropped. This inevitably leads to deadlock in the executor.~~ Assuming we don't catch the unwind in ParallelExecutor, this will naturally kill the main thread.

### Alternatives
A final solution likely will incorporate elements of any or all of the following.

#### ~~Log and Ignore~~
~~Log the panic, drop the task, keep chugging. This only addresses the discoverability of the panic. The process will continue to run, probably deadlocking the executor. tokio's detatched tasks operate in this fashion.~~

Panics already do this by default, even when caught by `catch_unwind`.

#### ~~`catch_unwind` in `ParallelExecutor`~~
~~Add another layer catching system-level panics into the `ParallelExecutor`. How the executor continues when a core dependency of many systems fails to run is up for debate.~~

`async_task::Task`  bubbles up panics already, this will transitively push panics all the way to the main thread.

#### ~~Emulate/Copy `tokio::JoinHandle` with `Task<T>`~~
~~`tokio::JoinHandle<T>` bubbles up the panic from the underlying task when awaited. This can be transitively applied across other APIs that also use `Task<T>` like `Query::par_for_each` and `TaskPool::scope`, bubbling up the panic until it's either caught or it reaches the main thread.~~

`async_task::Task`  bubbles up panics already, this will transitively push panics all the way to the main thread.

#### Abort on Panic
The nuclear option. Log the error, abort the entire process on any thread in the task pool panicking. Definitely avoids any additional infrastructure for passing the panic around, and might actually lead to more efficient code as any unwinding is optimized out. However gives the developer zero options for dealing with the issue, a seemingly poor choice for debuggability, and prevents graceful shutdown of the process. Potentially an option for handling very low-level task management (a la #4740). Roughly takes the shape of:

```rust
struct AbortOnPanic;

impl Drop for AbortOnPanic {
   fn drop(&mut self) {
     abort!();
   }
}

let guard = AbortOnPanic;
// Run task
std::mem::forget(AbortOnPanic);
```

---

## Changelog

Changed: `bevy_tasks::TaskPool`'s threads  will no longer terminate permanently when a task scheduled onto them panics.
Changed: `bevy_tasks::Task` and`bevy_tasks::Scope` will propagate panics in the spawned tasks/scopes to the parent thread.
2022-11-02 23:40:08 +00:00
..
bevy_animation Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_app Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_asset Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_audio Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_core Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_core_pipeline Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_derive Bump Version after Release (#5576) 2022-08-05 02:03:05 +00:00
bevy_diagnostic Add Exponential Moving Average into diagnostics (#4992) 2022-10-24 13:46:37 +00:00
bevy_dylib Bump Version after Release (#5576) 2022-08-05 02:03:05 +00:00
bevy_dynamic_plugin bevy_dynamic_plugin: make it possible to handle loading errors (#6437) 2022-11-01 11:35:44 +00:00
bevy_ecs TaskPool Panic Handling (#6443) 2022-11-02 23:40:08 +00:00
bevy_ecs_compile_fail_tests fix: specify required trybuild patch version (#6333) 2022-10-25 10:21:31 +00:00
bevy_encase_derive Bump Version after Release (#5576) 2022-08-05 02:03:05 +00:00
bevy_gilrs feat: add GamepadInfo, expose gamepad names (#6342) 2022-10-24 14:33:50 +00:00
bevy_gltf fix nightly clippy warnings (#6395) 2022-10-28 21:03:01 +00:00
bevy_hierarchy Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_input Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_internal Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_log Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_macro_utils fix nightly clippy warnings (#6395) 2022-10-28 21:03:01 +00:00
bevy_math Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_mikktspace Bump Version after Release (#5576) 2022-08-05 02:03:05 +00:00
bevy_pbr Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_ptr Bump Version after Release (#5576) 2022-08-05 02:03:05 +00:00
bevy_reflect Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_render Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_scene Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_sprite Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_tasks TaskPool Panic Handling (#6443) 2022-11-02 23:40:08 +00:00
bevy_text Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_time TaskPool Panic Handling (#6443) 2022-11-02 23:40:08 +00:00
bevy_transform TaskPool Panic Handling (#6443) 2022-11-02 23:40:08 +00:00
bevy_ui Add z-index support with a predictable UI stack (#5877) 2022-11-02 22:06:04 +00:00
bevy_utils Remove Sync bound from Local (#5483) 2022-09-12 04:15:55 +00:00
bevy_window Revert "Show prelude re-exports in docs (#6448)" (#6449) 2022-11-02 20:40:45 +00:00
bevy_winit do not set cursor grab on window creation if not asked for (#6381) 2022-10-31 16:12:18 +00:00