【问题标题】:Keep @RequestScoped context when receiving an async CDI event接收异步 CDI 事件时保留 @RequestScoped 上下文
【发布时间】:2022-10-12 23:25:23
【问题描述】:

我想从同步触发 CDI bean 切换到异步,以便能够并行工作。

event.fire(myObject) -> event.fireAsync(myObject)

由于我目前使用请求上下文来了解当前进程是关于哪个租户的,所以我遇到了一个问题,@RequestScoped 上下文在 @ObservesAsync 方法中丢失了。因此,我不再知道要保留什么数据库等。我可以在 cdi 事件对象中提供必要的信息,并在接收后手动重新创建请求上下文,但这会使我的对象膨胀并使我的代码混乱。

有没有办法简单地保留异步 cdi 事件的请求上下文?

【问题讨论】:

    标签: asynchronous jakarta-ee scope cdi quarkus


    【解决方案1】:

    请求范围的对象不需要是线程安全的,通常不是。因此,请求上下文永远不会跨线程自动传播。对于异步事件,确实应该将所有必要的数据放入事件对象中。

    你当然不是第一个问这个问题的人。已经尝试为上下文传播(MicroProfile Context Propagation,Jakarta Concurrency)定义一个 API/SPI,包括 CDI 请求上下文,但它们仅在带有线程跳转的顺序处理的情况下才能正常工作(在非阻塞/反应式编程中很常见)。如果您尝试 [ab] 使用上下文传播进行并发处理,那么您将遇到麻烦。有关此问题的最新讨论,请参阅https://github.com/jakartaee/cdi/issues/474

    【讨论】:

      【解决方案2】:

      我实际上切换到使用接口。这给了我更多的控制权并使代码更容易理解:

      abstract class Publisher<T>{
      
          @All
          @Inject
          private List<EventConsumer<T>> eventConsumers;
      
          @Inject
          private ContextInfo contextInfo;
      
          @Inject
          private MutableContextInfo mutableContextInfo;
      
          ...
      
          public void publishEvent(T event){
              String myContextInfo= contextInfo.getMyContextInfo();
              eventConsumers.forEach(consumer -> notifyAsync(consumer, receivedObject, myContextInfo))
          }
      
          private void notifyAsync(EventConsumer<T> consumer, T object, String myContextInfo) {
              Uni.createFrom()
                      .voidItem()
                      .subscribeAsCompletionStage()
                      .thenAccept(voidItem -> notifyConsumer(consumer, object, myContextInfo));
          }
      
          /**
           * Method needs to be public to be able to activate request context on self invocation
           */
          @ActivateRequestContext
          public void notifyConsumer(EventConsumer<T> consumer, T object, String myContextInfo) {
              mutableContextInfo.setMyContextInfo(myContextInfo);
              try {
                  consumer.onEvent(object);
              } catch (RuntimeException ex) {
                  log.error("Error while promoting object to eventconsumer", ex);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2018-12-26
        • 2017-08-30
        • 1970-01-01
        • 2017-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-30
        • 2015-07-14
        相关资源
        最近更新 更多