Repository: actix/actix (language: rust)

Issue:
May panic in finalization when the context is used in `Actor::started()`
## Version

* v0.9.0
* master

## Platform

This issue occurs at least on:

* Linux
* macOS

## Description

In some situations, `Actor::started()` may be called in the finalization.  In these cases, using the context in `Actor::started()` panics.
https://github.com/masnagam/rust-case-studies/blob/master/actix-started-in-drop/src/main.rs

## Expected Behavior

`Actor::started()` shouldn't be called in the finalization.

## Workaround

https://github.com/masnagam/rust-case-studies/tree/master/actix-started-in-drop#workaround


Discussion / hints:
I can confirm that this happens on upstream too.
The problemas semas to be that tokio calls panic when `tokio::time::delay_for` is called without the Runtime running even if we never `poll` it. The actor start is actually done asynchronously as it's lifetime is processed by a `Future`. Mostly likely it's being polled a single time as the system is shutting down causing the panic.

I'll look some more into this soon.
`MyActor::started()` is called from [ContextFut<A, C>::drop()](https://github.com/actix/actix/blame/b7c7237223dae46d27426799a48b4354c4376f54/src/contextimpl.rs#L231) which is called in the cancellation of a task.

```
started (/workspaces/rust-case-studies/actix-started-in-drop/src/main.rs:20)
poll<actix_started_in_drop::MyActor,actix::context::Context<actix_started_in_drop::MyActor>> (/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.9.0/src/contextimpl.rs:348)
...
do_cancel<actix::contextimpl::ContextFut<actix_started_in_drop::MyActor, actix::context::Context<actix_started_in_drop::MyActor>>,tokio::task::local::Scheduler> (/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.13/src/task/harness.rs:355)
cancel<actix::contextimpl::ContextFut<actix_started_in_drop::MyActor, actix::context::Context<actix_started_in_drop::MyActor>>,tokio::task::local::Scheduler> (/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.13/src/task/harness.rs:338)
cancel<actix::contextimpl::ContextFut<actix_started_in_drop::MyActor, actix::context::Context<actix_started_in_drop::MyActor>>,tokio::task::local::Scheduler> (/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.13/src/task/raw.rs:196)
cancel_from_queue (/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.13/src/task/raw.rs:145)
shutdown<tokio::task::local::Scheduler> (/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.13/src/task/mod.rs:395)
...
```
Calling the poll function in the drop was introduced at https://github.com/actix/actix/commit/2b13172b55cd2a1cc10fe68af5144f7549db0185 and modified at https://github.com/actix/actix/pull/300/commits/c4d77564eee9c770c59b26a8387aeddc019d6919.  Unfortunately, I cannot find reasons for those commits in this repository.  Probably, we need to ask @fafhrd91 and @bcmcmill about the reasons.


Fix patch:
diff --git a/CHANGES.md b/CHANGES.md
index c31222441..029a37a7e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -6,9 +6,13 @@
 
 * Update `tokio-util` dependency to 0.3, `FramedWrite` trait bound is changed. [#365]
 
+* Only poll dropped ContextFut if event loop is running. [#374]
+
 * Minimum Rust version is now 1.40 (to be able to use `#[cfg(doctest)]`)
 
+
 [#365]: https://github.com/actix/actix/pull/365
+[#374]: https://github.com/actix/actix/pull/374
 
 ## Fixed
 
diff --git a/Cargo.toml b/Cargo.toml
index 16fe02b06..6690143b9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,7 +33,7 @@ resolver = ["trust-dns-proto", "trust-dns-resolver"]
 mailbox_assert = []
 
 [dependencies]
-actix-rt = "1.0.0"
+actix-rt = "1.1"
 actix_derive = "0.5"
 bytes = "0.5.3"
 crossbeam-channel = "0.4"
diff --git a/src/contextimpl.rs b/src/contextimpl.rs
index b511ee583..b440857ed 100644
--- a/src/contextimpl.rs
+++ b/src/contextimpl.rs
@@ -224,7 +224,7 @@ where
     A: Actor<Context = C>,
 {
     fn drop(&mut self) {
-        if self.alive() {
+        if self.alive() && actix_rt::Arbiter::is_running() {
             self.ctx.parts().stop();
             let waker = futures_util::task::noop_waker();
             let mut cx = futures_util::task::Context::from_waker(&waker);


Test patch: