So, I'm going to start quite far back to describe exactly why tokio-async-await and futures(0.3)::compat are incompatible.
First of all, the design of both futures(0.1)::Future and std::future::Future are based on a scheme where you spawn a future as a "task" onto an "executor" to run it. The executor will poll the future once then park it until it gets a notification that the task is ready to run again. Running the future and routing the notification from the underlying async IO provided by the OS are completely decoupled (the latter is commonly called the "reactor", in Tokio's case they allow you to run both on the same thread for better performance).
With futures(0.1) this notification is handled by futures(0.1)::task::Task, the executor ensures that Task::current() will magically (via thread local storage) return a handle that can be used to notify it about readiness of the current task (IMO this naming is confusing because the Task is not the task, it is just a notification handle for the task, I will consistently use code formatting to distinguish them).
With std::futures::Future the notification is handled by std::task::Waker, the executor will pass a reference to a waker for the current task into the future as part of the std::task::Context.
Now, tokio-async-await has one purpose: to allow you to write async fn and async {} using Tokio's IO running on Tokio's executor. Because Task::current() is magic and will implicitly propagate through any intermediate std::future::Future it can ignore the std::task::Waker and just inject a dummy that doesn't work. Once you get down to an IO future that actually needs to register for notifications with the reactor it can just call Task::current() and acquire the handle that the executor stashed away earlier.
With futures(0.3)::compat the aim is to have a fully general bi-directional compatibility layer, allowing you to run std::future::Future on a futures(0.1) based executor, or run futures(0.1)::Future on a std::task based executor, or poll either as part of a larger future constructed from either types. To make this work in all cases it must translate between these two waker systems, when you use .compat() to convert a std::future::Future into a futures(0.1)::Future we add a layer that will call Task::current() to acquire the current notification handle and then wrap that into a type that implements std::task::Waker and pass this into the underlying std::future::Future, so if the underlying future attempts to call cx.waker().wake() this will then call task.notify() so that the futures(0.1) executor will see it. Similarly converting a futures(0.1)::Future into a std::future::Future will add a layer that takes the waker off the context and reconfigures Task::current() to return a Task that will call waker.wake() when task.notify() is called.
One consequence of these compatibility layers is that when you use futures(0.3)::compat to run a futures(0.1) based IO future on a futures(0.1) based executor with a middle layer of async fn we actually use both notification systems, the underlying IO future will call task.notify(), this goes into the Task that the 0.1 -> std compat layer setup which calls waker.wake(), which in turn goes into the Waker added by the std -> 0.1 compat layer which calls task.notify() on the Task setup by the executor.
The incompatibility comes from tokio-async-await assuming that Task::current will always return the Task setup by the executor. Because futures(0.3)::compat overrides this with a Task that proxies through to the Waker it was provided it breaks this underlying assumption.
You should be able to do something very close to your old implementation, just using combinators to convert the std::future::Future that async move gives you to a futures(0.1)::Future.
tokio::spawn(async move {
let response = await!(handle_request(pool)).unwrap();
println!("{}", response);
}.unit_error().boxed().compat());