Repository: quarkusio/quarkus
Issue: The exceptions thrown into an event flow (or a separate thread) are quietly captured and the developer won´t know it 

**Describe the bug**
In the code into an event handler method or another way to generate a separate thread (for example created using _Executors.newSingleThreadExecutor()_ or something like that) the exceptions are not reported, it seems they are quietly captured in an external layer. 

**Expected behavior**
In this code: 
```
@ApplicationScoped
public class EventsAndExceptions {

    private static final Logger LOGGER = Logger.getLogger(EventsAndExceptions.class.getCanonicalName());

    @Inject
    EventBus bus;

    @ConsumeEvent("greeting")
    public void consume(String name) {
        LOGGER.log(Level.INFO, "Hello {0}", name.toUpperCase());

        String nullReference = null;
        nullReference.toUpperCase();

        LOGGER.log(Level.INFO, "See you soon {0}", name.toUpperCase());
    }

    void startup(@Observes StartupEvent event) {
        bus.publish("greeting", "Vicent");
    }
}
```

```2021-01-25 20:30:09,627 INFO  [org.acm.EventsAndExceptions] (vert.x-eventloop-thread-1) Hello VICENT```

I expected the application to show the error, but it shows error nowhere. As expected, the last INFO log isn´t executed  because the flow has been interrupted at the forced NPE, but the developer won´t know it

If I capture explicitly the exception, evidently the catch block is invoked and the flow continues reaching the INFO log. 
```
String nullReference = null;
try {
     nullReference.toUpperCase();
} catch (Exception e) {
      LOGGER.log(Level.SEVERE, "Yes, this is a NPE", e);
}
```
```2021-01-25 20:30:09,627 INFO  [org.acm.EventsAndExceptions] (vert.x-eventloop-thread-1) Hello VICENT
2021-01-25 20:30:09,633 SEVERE [org.acm.EventsAndExceptions] (vert.x-eventloop-thread-1) Yes, this is a NPE: java.lang.NullPointerException
   at org.acme.EventsAndExceptions.consume(EventsAndExceptions.java:28)
   at org.acme.EventsAndExceptions_ClientProxy.consume(EventsAndExceptions_ClientProxy.zig:188)
...
   at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
   at java.base/java.lang.Thread.run(Thread.java:834)
2021-01-25 20:30:09,635 INFO  [org.acm.EventsAndExceptions] (vert.x-eventloop-thread-1) See you soon VICENT
```

Am I doing something wrong?

**Actual behavior**
The application doest´t notify about the exception has been thown. 


**To Reproduce**
I attach this zip file [this zip file](https://github.com/quarkusio/quarkus/files/5869258/code-with-quarkus-exceptions.zip)  with a fresh project using only _vertx_ and _resteasy-mutiny_ extensions to have events support. 

Steps to reproduce the behavior:
1. Unzip the file
2. Change to its directory and execute it: _./mvnw compile quarkus:dev_ 

**Configuration**
Not applicable

**Screenshots**
Not necessary

**Environment (please complete the following information):**
 - Output of `uname -a` or `ver`: 
 ```
Darwin iMac-de-Vicente-4.local 19.6.0 Darwin Kernel Version 19.6.0: Tue Nov 10 00:10:30 PST 2020; root:xnu-6153.141.10~1/RELEASE_X86_64 x86_64
```
- Output of `java -version`: 
 ```
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)
```
 - GraalVM version (if different from Java): GraalVM CE 20.3.1
 - Quarkus version or git rev: 1.11.0.Final
 - Build tool (ie. output of `mvnw --version` or `gradlew --version`): 
```
Maven home: /Users/vferrer/.m2/wrapper/dists/apache-maven-3.6.3-bin/1iopthnavndlasol9gbrbg6bf2/apache-maven-3.6.3
Java version: 11.0.2, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home
Default locale: es_ES, platform encoding: UTF-8
OS name: "mac os x", version: "10.15.7", arch: "x86_64", family: "mac"
```

Changed files:
extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java
extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/EventBusConsumer.java
extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java
extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxRecorder.java
extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java
extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanInvoker.java
extensions/vertx/deployment/src/test/java/io/quarkus/vertx/deployment/MessageConsumerFailureTest.java

diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanInvoker.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanInvoker.java
index d0a0741e3e4..ed4c248a87b 100644
--- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanInvoker.java
+++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanInvoker.java
@@ -10,7 +10,7 @@
  */
 public interface BeanInvoker<T> {
 
-    default void invoke(T param) {
+    default void invoke(T param) throws Exception {
         ManagedContext requestContext = Arc.container().requestContext();
         if (requestContext.isActive()) {
             invokeBean(param);
@@ -24,6 +24,6 @@ default void invoke(T param) {
         }
     }
 
-    void invokeBean(T param);
+    void invokeBean(T param) throws Exception;
 
 }
diff --git a/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java b/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java
index 3798ecc8f9a..24829c01148 100644
--- a/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java
+++ b/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java
@@ -26,6 +26,7 @@
 import org.quartz.JobBuilder;
 import org.quartz.JobDetail;
 import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
 import org.quartz.ScheduleBuilder;
 import org.quartz.SchedulerException;
 import org.quartz.SchedulerFactory;
@@ -378,11 +379,15 @@ static class InvokerJob implements Job {
         }
 
         @Override
-        public void execute(JobExecutionContext context) {
+        public void execute(JobExecutionContext context) throws JobExecutionException {
             QuartzTrigger trigger = new QuartzTrigger(context);
             ScheduledInvoker scheduledInvoker = invokers.get(context.getJobDetail().getKey().getName());
             if (scheduledInvoker != null) { // could be null from previous runs
-                scheduledInvoker.invoke(new QuartzScheduledExecution(trigger));
+                try {
+                    scheduledInvoker.invoke(new QuartzScheduledExecution(trigger));
+                } catch (Exception e) {
+                    throw new JobExecutionException(e);
+                }
             }
         }
     }
diff --git a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java
index 79541952a95..1d2c3311699 100644
--- a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java
+++ b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java
@@ -263,7 +263,8 @@ private String generateInvoker(ScheduledBusinessMethodItem scheduledMethod, Clas
                 .build();
 
         // The descriptor is: void invokeBean(Object execution)
-        MethodCreator invoke = invokerCreator.getMethodCreator("invokeBean", void.class, Object.class);
+        MethodCreator invoke = invokerCreator.getMethodCreator("invokeBean", void.class, Object.class)
+                .addException(Exception.class);
         // InjectableBean<Foo: bean = Arc.container().bean("1");
         // InstanceHandle<Foo> handle = Arc.container().instance(bean);
         // handle.get().ping();
diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java
index 9ece757b620..26b3658b473 100644
--- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java
+++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java
@@ -31,7 +31,7 @@ public SkipConcurrentExecutionInvoker(ScheduledInvoker delegate, Event<SkippedEx
     }
 
     @Override
-    public void invoke(ScheduledExecution execution) {
+    public void invoke(ScheduledExecution execution) throws Exception {
         if (running.compareAndSet(false, true)) {
             try {
                 delegate.invoke(execution);
diff --git a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/EventBusConsumer.java b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/EventBusConsumer.java
index 65a4e3454db..c22e827afcf 100644
--- a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/EventBusConsumer.java
+++ b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/EventBusConsumer.java
@@ -102,7 +102,8 @@ static String generateInvoker(BeanInfo bean, MethodInfo method,
                 .interfaces(EventConsumerInvoker.class).build();
 
         // The method descriptor is: void invokeBean(Object message)
-        MethodCreator invoke = invokerCreator.getMethodCreator("invokeBean", void.class, Object.class);
+        MethodCreator invoke = invokerCreator.getMethodCreator("invokeBean", void.class, Object.class)
+                .addException(Exception.class);
 
         if (blocking) {
             MethodCreator isBlocking = invokerCreator.getMethodCreator("isBlocking", boolean.class);
diff --git a/extensions/vertx/deployment/src/test/java/io/quarkus/vertx/deployment/MessageConsumerFailureTest.java b/extensions/vertx/deployment/src/test/java/io/quarkus/vertx/deployment/MessageConsumerFailureTest.java
index fd6a95316e5..915097d4adb 100644
--- a/extensions/vertx/deployment/src/test/java/io/quarkus/vertx/deployment/MessageConsumerFailureTest.java
+++ b/extensions/vertx/deployment/src/test/java/io/quarkus/vertx/deployment/MessageConsumerFailureTest.java
@@ -20,6 +20,8 @@
 import io.quarkus.test.QuarkusUnitTest;
 import io.quarkus.vertx.ConsumeEvent;
 import io.smallrye.mutiny.Uni;
+import io.vertx.core.Handler;
+import io.vertx.core.Vertx;
 import io.vertx.core.eventbus.EventBus;
 import io.vertx.core.eventbus.Message;
 import io.vertx.core.eventbus.ReplyException;
@@ -33,6 +35,9 @@ public class MessageConsumerFailureTest {
     @Inject
     SimpleBean simpleBean;
 
+    @Inject
+    Vertx vertx;
+
     @Inject
     EventBus eventBus;
 
@@ -53,6 +58,30 @@ public void testFailure() throws InterruptedException {
         verifyFailure("foo-uni-failure-blocking", "boom", true);
     }
 
+    @Test
+    public void testFailureNoReplyHandler() throws InterruptedException {
+        Handler<Throwable> oldHandler = vertx.exceptionHandler();
+        try {
+            BlockingQueue<Object> synchronizer = new LinkedBlockingQueue<>();
+            vertx.exceptionHandler(new Handler<Throwable>() {
+                @Override
+                public void handle(Throwable event) {
+                    try {
+                        synchronizer.put(event);
+                    } catch (InterruptedException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+            });
+            eventBus.send("foo", "bar");
+            Object ret = synchronizer.poll(2, TimeUnit.SECONDS);
+            assertTrue(ret instanceof IllegalStateException);
+            assertEquals("Foo is dead", ((IllegalStateException) ret).getMessage());
+        } finally {
+            vertx.exceptionHandler(oldHandler);
+        }
+    }
+
     void verifyFailure(String address, String expectedMessage, boolean explicit) throws InterruptedException {
         BlockingQueue<Object> synchronizer = new LinkedBlockingQueue<>();
         eventBus.request(address, "hello", ar -> {
diff --git a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxRecorder.java b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxRecorder.java
index d656fad5029..b84270f741e 100644
--- a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxRecorder.java
+++ b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxRecorder.java
@@ -88,8 +88,13 @@ public void handle(Message<Object> m) {
                                 public void handle(Promise<Object> event) {
                                     try {
                                         invoker.invoke(m);
-                                    } catch (Throwable e) {
-                                        m.fail(ConsumeEvent.FAILURE_CODE, e.toString());
+                                    } catch (Exception e) {
+                                        if (m.replyAddress() == null) {
+                                            // No reply handler
+                                            throw wrapIfNecessary(e);
+                                        } else {
+                                            m.fail(ConsumeEvent.FAILURE_CODE, e.toString());
+                                        }
                                     }
                                     event.complete();
                                 }
@@ -97,8 +102,13 @@ public void handle(Promise<Object> event) {
                         } else {
                             try {
                                 invoker.invoke(m);
-                            } catch (Throwable e) {
-                                m.fail(ConsumeEvent.FAILURE_CODE, e.toString());
+                            } catch (Exception e) {
+                                if (m.replyAddress() == null) {
+                                    // No reply handler
+                                    throw wrapIfNecessary(e);
+                                } else {
+                                    m.fail(ConsumeEvent.FAILURE_CODE, e.toString());
+                                }
                             }
                         }
                     }
@@ -123,6 +133,14 @@ public void handle(AsyncResult<Void> ar) {
         }
     }
 
+    private RuntimeException wrapIfNecessary(Exception e) {
+        if (e instanceof RuntimeException) {
+            return (RuntimeException) e;
+        } else {
+            return new RuntimeException(e);
+        }
+    }
+
     void unregisterMessageConsumers() {
         CountDownLatch latch = new CountDownLatch(messageConsumers.size());
         for (MessageConsumer<?> messageConsumer : messageConsumers) {