[weld-issues] [JBoss JIRA] Updated: (WELD-862) Interceptors not threadsafe

Marius Bogoevici (JIRA) jira-events at lists.jboss.org
Mon May 16 02:17:01 EDT 2011


     [ https://issues.jboss.org/browse/WELD-862?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Marius Bogoevici updated WELD-862:
----------------------------------

    Issue Type: Enhancement  (was: Bug)


OK, a few comments about this issue. I set it as an Enhancement, since this is not something supported by the specification.

The interceptor code and the intercepted method must execute in the same call stack, which is not the case here. The specification itself leaves little room for supporting a call to proceed() from outside the original call stack because an InvocationContext is supposed to be a mutable, stateful instance (since according to the specification, the *same* instance must be passed along the chain of interceptors). At the same time, interceptors must support recovery, which means that subsequent calls to proceed() will execute the whole interceptor chain again, as in the following example:

{code}
try 
{
  ctx.proceed();
} 
catch (Exception e) 
{
   ctx.proceed();
}
{code}

which is why the state of the interceptor chain is always restored at the end of a proceed() invocation. 

>From this, it follows that the problem is not necessarily a thread safety issue, but a race condition introduced by the asynchronous interceptor implementation - it is impossible to know whether the next call to ctx.proceed() will happen before or after the interceptor method returns - and if it happens after, it is exactly as if the preceding interceptor itself has called proceed(), which requires to execute the following chain of interceptors again, including the current one. 

This works in Open Web Beans because of an actual issue there - https://issues.apache.org/jira/browse/OWB-570, due to which interceptor executions are not actually recoverable.

One possible solution is to ignore the requirement of passing the same instance along and pass a different immutable InvocationContext on each interceptor call. This is, however, a violation of the specification in itself, so I would like to consider the implications before moving forward with it.

However, even if we decide how to support this in Weld, the interceptor code itself is non-portable, since an implementation cannot be required to support this behaviour. An alternative solution would be to copy the InvocationContext, which will probably need to be implemented for each CDI implementation in particular.

> Interceptors not threadsafe
> ---------------------------
>
>                 Key: WELD-862
>                 URL: https://issues.jboss.org/browse/WELD-862
>             Project: Weld
>          Issue Type: Enhancement
>          Components: Interceptors and Decorators
>    Affects Versions: 1.1.0.Final
>         Environment: Jetty, Weld Filter
>            Reporter: Sebastian Schaffert
>            Assignee: Marius Bogoevici
>
> I am trying to implement an "@Asynchronous" interceptor that runs methods annotated with the @Asynchronous annotation in a separate thread. The implementation of the interceptor currently looks as follows:
>     private static final ThreadGroup asyncMethods = new ThreadGroup("asynchronous method invocations");
>     @AroundInvoke
>     public Object manageAsynchronous(final InvocationContext ctx) throws Exception {
>         final UUID threadID = UUID.randomUUID();
>         Runnable r = new Runnable() {
>             @Override
>             public void run() {
>                 try {
>                     log.debug("asynchronous method invocation of {}.{} (Thread ID {})",new Object[] {ctx.getTarget().getClass().getName(),ctx.getMethod().getName(), threadID});
>                     Object val = ctx.proceed();
>                     if(val != null) {
>                         log.debug("asynchronous method invocation of {}.{} (Thread ID {}) returned value {}",new Object[] {ctx.getClass().getName(),ctx.getMethod().getName(), threadID, val});
>                     }
>                 } catch(Exception ex) {
>                     log.error("exception during asynchronous method invocation",ex);
>                 }
>             }
>         };
>         Thread t = new Thread(asyncMethods,r);
>         t.setName("asynchronous method invocation of "+ctx.getTarget().getClass().getName()+ctx.getMethod().getName() + " (Threaad ID " + threadID+")");
>         t.start();
>         return null;
>     }
> Now the problem is that the interceptor is called infinitely often. The reason is that the annotated method forks a new thread and then returns instantly, setting the variable "currentPosition" in SimpleInterceptorChain back to the value 0 (in a "finally" block). So when the proceed() method is called inside the thread, the interceptor chain again points to the first interceptor in the chain and it all repeats infinitely.

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the weld-issues mailing list