[ https://issues.apache.org/jira/browse/CXF-2792?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Leo Romanoff updated CXF-2792: ------------------------------ Labels: asynchronous Executor invokeasync concurrency (was: invokeAsync asynchronous Executor) Description: Hi, I'm trying to invoke 10000 external services using invokeAsync from my standalone JAX-WS client. I set my custom Executor on the Service objects. This executor is a ThreadPool with 3 threads. But it looks like it is ignored completely by the CXF run-time. Instead of an Executor, an instance of AutomaticWorkQueueImpl is used. BTW, by default, AutomaticWorkQueueImpl is an unbounded queue, so that a few thousands threads are created for processing asynchronous responses. This is of cause problematic and has a big performance impact. By providing the configuration for AutomaticWorkQueueImpl in cxf.xml, the AutomaticWorkQueueImpl can be configured to have a required number of threads and required maximum capacity. So, I did some debugging to see, why and where AutomaticWorkQueueImpl is called at all during asynchronous WS invocations using Dispatch.invokeAsync(). This is the stack trace I got: Thread [main] (Suspended (entry into method execute in AutomaticWorkQueueImpl)) AutomaticWorkQueueImpl.execute(Runnable) line: 247 HTTPConduit$WrappedOutputStream.handleResponse() line: 2153 HTTPConduit$WrappedOutputStream.close() line: 1988 HTTPConduit(AbstractConduit).close(Message) line: 66 HTTPConduit.close(Message) line: 639 MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(Message) line: 62 PhaseInterceptorChain.doIntercept(Message) line: 243 ClientImpl.invoke(ClientCallback, BindingOperationInfo, Object...) line: 422 ClientImpl.invokeWrapped(ClientCallback, QName, Object...) line: 371 DispatchImpl<T>.invokeAsync(T, AsyncHandler<T>) line: 288 TestAsyncProviderClient.invokeMyDispatch(Dispatch<Source>, Object, AsyncHandler<Source>) line: 298 TestAsyncProviderClient.testManyAsyncResponses() line: 218 TestAsyncProviderClient.main(String[]) line: 159 According to this trace, WS-response processing at the HTTP level is put for the execution on a dedicated working queue in the HTTPConduit.handleResponse method: protected void handleResponse() throws IOException { handleRetransmits(); if (outMessage == null || outMessage.getExchange() == null || outMessage.getExchange().isSynchronous()) { handleResponseInternal(); } else { Runnable runnable = new Runnable() { public void run() { try { handleResponseInternal(); } catch (Exception e) { Message inMessage = new MessageImpl(); inMessage.setExchange(outMessage.getExchange()); inMessage.setContent(Exception.class, e); incomingObserver.onMessage(inMessage); } } }; WorkQueueManager mgr = outMessage.getExchange().get(Bus.class) .getExtension(WorkQueueManager.class); AutomaticWorkQueue queue = mgr.getNamedWorkQueue("http-conduit"); if (queue == null) { queue = mgr.getAutomaticWorkQueue(); } queue.execute(runnable); } } It is easy to see that Executor set for the JAX-WS Service is not propagated down to the HTTP transoport level, which required dedicated configuration for AutomaticWorkQueue, be it http-conduit queue or automatic work queue. For WS-responses at the user-level, i.e. by means of the JAX-WS AsyncHandler handlers, the proper Executor is taken from the Service object. See also the discussion on the mailing list: http://old.nabble.com/RejectedExecutionException-when-doing-many-invokeAsync-invocations-ts28266640.html was: Hi, I'm trying to invoke 10000 external services using invokeAsync from my standalone JAX-WS client. I set my custom Executor on the Service objects. This executor is a ThreadPool with 3 threads. But it looks like it is ignored completely by the CXF run-time. Instead of an Executor, an instance of AutomaticWorkQueueImpl is used. BTW, by default, AutomaticWorkQueueImpl is an unbounded queue, so that a few thousands threads are created for processing asynchronous responses. This is of cause problematic and has a big performance impact. By providing the configuration for AutomaticWorkQueueImpl in cxf.xml, the AutomaticWorkQueueImpl can be configured to have a required number of threads and required maximum capacity. So, I did some debugging to see, why and where AutomaticWorkQueueImpl is called at all during asynchronous WS invocations using Dispatch.invokeAsync(). This is the stack trace I got: Thread [main] (Suspended (entry into method execute in AutomaticWorkQueueImpl)) AutomaticWorkQueueImpl.execute(Runnable) line: 247 HTTPConduit$WrappedOutputStream.handleResponse() line: 2153 HTTPConduit$WrappedOutputStream.close() line: 1988 HTTPConduit(AbstractConduit).close(Message) line: 66 HTTPConduit.close(Message) line: 639 MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(Message) line: 62 PhaseInterceptorChain.doIntercept(Message) line: 243 ClientImpl.invoke(ClientCallback, BindingOperationInfo, Object...) line: 422 ClientImpl.invokeWrapped(ClientCallback, QName, Object...) line: 371 DispatchImpl<T>.invokeAsync(T, AsyncHandler<T>) line: 288 TestAsyncProviderClient.invokeMyDispatch(Dispatch<Source>, Object, AsyncHandler<Source>) line: 298 TestAsyncProviderClient.testManyAsyncResponses() line: 218 TestAsyncProviderClient.main(String[]) line: 159 According to this trace, WS-response processing at the HTTP level is put for the execution on a dedicated working queue in the HTTPConduit.handleResponse method: protected void handleResponse() throws IOException { // Process retransmits until we fall out. handleRetransmits(); if (outMessage == null || outMessage.getExchange() == null || outMessage.getExchange().isSynchronous()) { handleResponseInternal(); } else { Runnable runnable = new Runnable() { public void run() { try { handleResponseInternal(); } catch (Exception e) { Message inMessage = new MessageImpl(); inMessage.setExchange(outMessage.getExchange()); inMessage.setContent(Exception.class, e); incomingObserver.onMessage(inMessage); } } }; WorkQueueManager mgr = outMessage.getExchange().get(Bus.class) .getExtension(WorkQueueManager.class); AutomaticWorkQueue queue = mgr.getNamedWorkQueue("http-conduit"); if (queue == null) { queue = mgr.getAutomaticWorkQueue(); } queue.execute(runnable); } } It is easy to see that Executor set for the JAX-WS Service is not propagated down to the HTTP transoport level, which required dedicated configuration for AutomaticWorkQueue, be it http-conduit queue or automatic work queue. For WS-responses at the user-level, i.e. by means of the JAX-WS AsyncHandler handlers, the proper Executor is taken from the Service object. > Custom Executor for Service object is ignored by the CXF JAX-WS run-time when > Disaptch.invokeAsync is used > ---------------------------------------------------------------------------------------------------------- > > Key: CXF-2792 > URL: https://issues.apache.org/jira/browse/CXF-2792 > Project: CXF > Issue Type: Bug > Components: JAX-WS Runtime > Affects Versions: 2.2.7 > Environment: Standalone CXF-client used on Windows Vista > Reporter: Leo Romanoff > > Hi, > I'm trying to invoke 10000 external services using invokeAsync from my > standalone JAX-WS client. > I set my custom Executor on the Service objects. This executor is a > ThreadPool with 3 threads. But it looks like it is ignored completely by the > CXF > run-time. Instead of an Executor, an instance of AutomaticWorkQueueImpl is > used. > BTW, by default, AutomaticWorkQueueImpl is an unbounded queue, so that a few > thousands threads are created for processing asynchronous responses. This is > of cause problematic and has a big performance impact. By providing the > configuration for AutomaticWorkQueueImpl in cxf.xml, the > AutomaticWorkQueueImpl can be configured to have a required number of > threads and required maximum capacity. > So, I did some debugging to see, why and where AutomaticWorkQueueImpl is > called at all during asynchronous WS invocations using > Dispatch.invokeAsync(). > This is the stack trace I got: > Thread [main] (Suspended (entry into method execute in > AutomaticWorkQueueImpl)) > AutomaticWorkQueueImpl.execute(Runnable) line: 247 > HTTPConduit$WrappedOutputStream.handleResponse() line: 2153 > HTTPConduit$WrappedOutputStream.close() line: 1988 > HTTPConduit(AbstractConduit).close(Message) line: 66 > HTTPConduit.close(Message) line: 639 > > MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(Message) > line: 62 > PhaseInterceptorChain.doIntercept(Message) line: 243 > ClientImpl.invoke(ClientCallback, BindingOperationInfo, Object...) > line: 422 > ClientImpl.invokeWrapped(ClientCallback, QName, Object...) line: 371 > DispatchImpl<T>.invokeAsync(T, AsyncHandler<T>) line: 288 > TestAsyncProviderClient.invokeMyDispatch(Dispatch<Source>, Object, > AsyncHandler<Source>) line: 298 > TestAsyncProviderClient.testManyAsyncResponses() line: 218 > TestAsyncProviderClient.main(String[]) line: 159 > According to this trace, WS-response processing at the HTTP level is put for > the execution on a dedicated working queue in the HTTPConduit.handleResponse > method: > protected void handleResponse() throws IOException { > > handleRetransmits(); > > if (outMessage == null || outMessage.getExchange() == null || > outMessage.getExchange().isSynchronous()) { > handleResponseInternal(); > } else { > Runnable runnable = new Runnable() { > public void run() { > try { > handleResponseInternal(); > } catch (Exception e) { > Message inMessage = new MessageImpl(); > inMessage.setExchange(outMessage.getExchange()); > inMessage.setContent(Exception.class, e); > incomingObserver.onMessage(inMessage); > } > } > }; > WorkQueueManager mgr = > outMessage.getExchange().get(Bus.class) > .getExtension(WorkQueueManager.class); > AutomaticWorkQueue queue = > mgr.getNamedWorkQueue("http-conduit"); > if (queue == null) { > queue = mgr.getAutomaticWorkQueue(); > } > queue.execute(runnable); > } > } > It is easy to see that Executor set for the JAX-WS Service is not propagated > down to the HTTP transoport level, which required dedicated configuration for > AutomaticWorkQueue, be it http-conduit queue or automatic work queue. > For WS-responses at the user-level, i.e. by means of the JAX-WS AsyncHandler > handlers, the proper Executor is taken from the Service object. > See also the discussion on the mailing list: > http://old.nabble.com/RejectedExecutionException-when-doing-many-invokeAsync-invocations-ts28266640.html -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.