[cdi-dev] Building EJB-like @Asynchronous via interceptor in CDI

Romain Manni-Bucau rmannibucau at gmail.com
Sun Jan 18 14:46:12 EST 2015


+1
Le 18 janv. 2015 18:38, "arjan tijms" <arjan.tijms at gmail.com> a écrit :

> Hi
>
> On Sat, Jan 17, 2015 at 11:05 AM, Arne Limburg <
> arne.limburg at openknowledge.de> wrote:
> > Since we almost don’t use ThreadLocals in OWB, I guess, this should work
> out
> > of the box.
> > Did a quick check of the interceptor code and see no issues with handling
> > over the InvocationContext to another thread. However, the
> InvocationContext
> > has some internal state that could get confused, if proceed() is called
> in
> > parallel from two different threads, but that’s another thing. Just give
> it
> > a try and tell us about the result :-)
>
> I tested it on a OWB 1.5.0-SNAPSHOT from a few weeks back as part of
> TomEE-2.0-SNAPSHOT and using a simple example with a request scoped bean
> and no other interceptors it indeed worked out of the box :) Still have to
> test with some more complicated setups, but things look promising.
>
> I wonder, should anything still be spec'ed for this? Perhaps just a
> mention somewhere that this is indeed allowed, along with a TCK test?
>
> Kind regards,
> Arjan
>
>
>
>
> >
> > Cheers,
> > Arne
> >
> > Von: arjan tijms <arjan.tijms at gmail.com>
> > Datum: Samstag, 17. Januar 2015 00:32
> > An: Jozef Hartinger <jharting at redhat.com>
> > Cc: "cdi-dev at lists.jboss.org" <cdi-dev at lists.jboss.org>
> > Betreff: Re: [cdi-dev] Building EJB-like @Asynchronous via interceptor in
> > CDI
> >
> > Hi,
> >
> > On Fri, Jan 16, 2015 at 10:41 PM, Jozef Hartinger <jharting at redhat.com>
> > wrote:
> >>
> >> Hi Arjan,
> >>
> >> I did some changes recently in Weld interceptors and this usecase now
> >> works smoothly. The code is not part of a release yet. See this test
> for a
> >> simple implementation of an @Async interceptor (basically the same as
> your
> >> initial attempt). Note that the chain is repeatable but at the same
> time it
> >> is not reset after dispatch to a different thread so you no longer need
> the
> >> ThreadLocal nor any other workaround.
> >
> >
> > That's quite a coincidence, it's indeed rather similar ;)
> >
> > I wonder how it now works though, as the InvocationContext "ctx" does not
> > seem to be made aware that it's been dispatched to a different thread
> from
> > within the code. Does it use an internal thread local to keep state or
> so?
> >
> > I'll also try to see what this does on OWB. Do you think this is
> something
> > that should work, or just something that Weld happens to support
> regardless
> > of the spec?
> >
> > Kind regards,
> > Arjan
> >
> >
> >
> >>
> >>
> >>
> >>
> https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/thread/async/AsyncInterceptor.java
> >>
> >> Jozef
> >>
> >>
> >> On 01/16/2015 06:17 PM, arjan tijms wrote:
> >>
> >> Hi,
> >>
> >> I'm attempting to emulate EJB's @Asynchronous in CDI using interceptors.
> >>
> >> Originally I had defined my interceptor as follows;
> >>
> >> @Interceptor
> >> @Asynchronous
> >> @Priority(APPLICATION)
> >> public class AsynchronousInterceptor implements Serializable {
> >>
> >>     private static final long serialVersionUID = 1L;
> >>
> >>     @Resource
> >>     private ManagedExecutorService managedExecutorService;
> >>
> >>     @AroundInvoke
> >>     public Object submitAsync(InvocationContext ctx) throws Exception {
> >>         return new FutureDelegator(managedExecutorService.submit( ()-> {
> >> return ctx.proceed(); } ));
> >>     }
> >>
> >> }
> >>
> >> With FutureDelegator as follows:
> >>
> >> public class FutureDelegator implements Future<Object> {
> >>
> >>     private Future<?> future;
> >>
> >>     public FutureDelegator(Future<?> future) {
> >>         this.future = future;
> >>     }
> >>
> >>     @Override
> >>     public Object get() throws InterruptedException, ExecutionException
> {
> >>         AsyncResult<?> asyncResult = (AsyncResult<?>) future.get();
> >>         if (asyncResult == null) {
> >>             return null;
> >>         }
> >>
> >>         return asyncResult.get();
> >>     }
> >>
> >>     @Override
> >>     public Object get(long timeout, TimeUnit unit) throws
> >> InterruptedException,    ExecutionException, TimeoutException {
> >>         AsyncResult<?> asyncResult = (AsyncResult<?>)
> future.get(timeout,
> >> unit);
> >>         if (asyncResult == null) {
> >>             return null;
> >>         }
> >>
> >>         return asyncResult.get();
> >>     }
> >>
> >>     @Override
> >>     public boolean cancel(boolean mayInterruptIfRunning) {
> >>         return future.cancel(mayInterruptIfRunning);
> >>     }
> >>
> >>     @Override
> >>     public boolean isCancelled() {
> >>         return future.isCancelled();
> >>     }
> >>     @Override
> >>     public boolean isDone() {
> >>         return future.isDone();
> >>     }
> >>
> >> }
> >>
> >> This of course didn't quite work, as the InvocationContext will be reset
> >> after the @AroundInvoke method returns, and an infinite intercept loop
> >> results (on Weld).
> >>
> >> I got it to work though on Weld by using a thread local check to break
> >> that loop:
> >>
> >> @Interceptor
> >> @Asynchronous
> >> @Priority(PLATFORM_BEFORE)
> >> public class AsynchronousInterceptor implements Serializable {
> >>
> >>     private static final long serialVersionUID = 1L;
> >>
> >>     @Resource
> >>     private ManagedExecutorService managedExecutorService;
> >>
> >>     private static final ThreadLocal<Boolean> asyncInvocation = new
> >> ThreadLocal<Boolean>();
> >>
> >>     @AroundInvoke
> >>     public synchronized Object submitAsync(InvocationContext ctx) throws
> >> Exception {
> >>
> >>         if (TRUE.equals(asyncInvocation.get())) {
> >>             return ctx.proceed();
> >>         }
> >>
> >>         return new FutureDelegator(managedExecutorService.submit( ()-> {
> >>             try {
> >>                 asyncInvocation.set(TRUE);
> >>                 return ctx.proceed();
> >>             } finally {
> >>                  asyncInvocation.remove();
> >>             }
> >>         }));
> >>     }
> >>
> >> }
> >>
> >> But I've got a feeling this works just by chance and not because the
> >> workaround is so clever.
> >>
> >> What do you guys think, what would be the best way to support this with
> >> the current CDI version? Or would CDI/Interceptors need something like
> >> Servlet's async support, where the InvocationContext is put into async
> mode
> >> whereafter it "simply" allows an other thread to continue processing on
> it?
> >>
> >> Kind regards,
> >> Arjan Tijms
> >>
> >>
> >>
> >>
> >>
> >>
> >>
> >> _______________________________________________
> >> cdi-dev mailing list
> >> cdi-dev at lists.jboss.orghttps://lists.jboss.org/mailman/listinfo/cdi-dev
> >>
> >> Note that for all code provided on this list, the provider licenses the
> >> code under the Apache License, Version 2
> >> (http://www.apache.org/licenses/LICENSE-2.0.html). For all other ideas
> >> provided on this list, the provider waives all patent and other
> intellectual
> >> property rights inherent in such information.
> >>
> >>
> >
>
>
> _______________________________________________
> cdi-dev mailing list
> cdi-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/cdi-dev
>
> Note that for all code provided on this list, the provider licenses the
> code under the Apache License, Version 2 (
> http://www.apache.org/licenses/LICENSE-2.0.html). For all other ideas
> provided on this list, the provider waives all patent and other
> intellectual property rights inherent in such information.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/cdi-dev/attachments/20150118/36f178ec/attachment-0001.html 


More information about the cdi-dev mailing list