2017-08-22 10 views
0

Springブート1.5.4でjhipsterを使用すると、バックグラウンドタスクを非同期で実行するのに苦労しています。彼らは私が設定したものとは異なるtaskExecutorとスレッドプールを使って同期的に実行されているように見えます。Java Spring Async Execution

@Service 
@Transactional 
public class AppService { 
    @Scheduled(fixedDelay = 3000) 
    public void consumeData() { 
     // connect to a subscriber and push data to the workerBee 
     for(Tuple data : this.getTuples()) { 
      workerBee(data); 
     } 
    } 

    @Timed 
    @Async 
    public void workerBee(Tuple data) throws Exception { 
     // ... do something that takes 300ms .... 
     Thread.sleep(300); 
    } 
} 

は間違いなくサービスは、この作業に最適な場所ではなく、デモの目的のために、それがフィット:

このすべてがbevityのために、そのように定義されたサービスで起こります。

(また余談として、それは@Timedが動作していないapearsが、サービス内で内部的に呼び出されたとき、私は@Timedが動作しないことをどこかで読ん)application.yml

関連セクション:

jhipster: 
    async: 
     core-pool-size: 8 
     max-pool-size: 64 
     queue-capacity: 10000 
私はのTaskExecutor Beanが作成取得していることを確認し

@Override 
@Bean(name = "taskExecutor") 
public Executor getAsyncExecutor() { 
    log.debug("Creating Async Task Executor"); 
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
    executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); 
    executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); 
    executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); 
    executor.setThreadNamePrefix("app-Executor-"); 
    return new ExceptionHandlingAsyncTaskExecutor(executor); 
} 

と:デフォルトを使用して は

、このようになりますAsyncConfiguration.javaを、生成されましたliquibaseによって使用されています。

私がvisualvmに接続すると、何らかの種類のデフォルトでなければならないすべての作業がpool-2-thread-1で起きていることがわかります。作業は同期的に起きていて、非同期ではないことは明らかです。

物事は私が試してみた:

  • は、コアプールサイズで8つのスレッドでのTaskExecutorの構成を確認@Async注釈などの@Async("taskExecutor")
  • にexecutorを指定します。
  • アプリケーションに@EnableAsyncアノテーションがあることを確認します(デフォルトではこれが行われます)。

答えて

0

1つの選択肢は、これに@Bean getAsyncExecutorを変更している。

@Bean 
public ThreadPoolTaskExecutor threadPoolTaskExecutor() { 
    log.debug("Creating Async Task Executor"); 
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
    executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); 
    executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); 
    executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); 
    executor.setThreadNamePrefix("app-Executor-"); 
    return executor; 
} 
+0

。それがなぜ助けられるのでしょうか? –

+0

答えを無視するあなたはジプスターを使用しているとわかります –

0

オルタナティブ2:ここでは

CompletableFutureを使用して、同じクラスの非同期メソッドを呼び出している別のアプローチあなたがする必要がある場合非同期メソッドを使用し、CompletableFutureを使用して同じクラスで呼び出し、AsyncConfiguration

から生成された Executorを注入します
@Service 
public class MyAsyncProcess { 

    private final Logger log = LoggerFactory.getLogger(MyAsyncProcess.class); 

    @Autowired 
    Executor executor; 


    @Scheduled(cron = "*/8 * * * * *") 
    public void consumeData() { 

     IntStream.range(0,20).forEach((s) -> 
      CompletableFuture.supplyAsync(() -> { return workerBeeCompletableFuture(String.valueOf(s)); } , executor)); 
    } 


    public CompletableFuture<String> workerBeeCompletableFuture(String data) { 

     log.debug("workerBeeCompletableFuture: Iteration number: " + data + " Thread: " + Thread.currentThread().getName()); 

     try { Thread.sleep(2000); } 
     catch (InterruptedException e) { e.printStackTrace(); } 

     return CompletableFuture.completedFuture("finished"); 

    } 

@Async

を使用して代替1私は最終的にこの動作を引き起こしているものを得る、実際に​​は地元の方法としてではなく@Async方法としてworkerBeeに呼びかけています。 @Async仕事がちょうどMySchedulerServiceAppServiceMySchedulerService呼ば@Scheduleのための新しい@Serviceを作成し、@Autowiredにするために

。また、AppServiceクラスから@Scheduleを削除します。

それはこのようにする必要があり

jhipster: 
    async: 
     core-pool-size: 50 
     max-pool-size: 100 
     queue-capacity: 10000 

@AsyncExecutorを自動検出します:私は次の値を使用application.yml

@Service 
public class MyAsyncProcess { 

    private final Logger log = LoggerFactory.getLogger(MyAsyncProcess.class); 

    @Async 
    public void workerBeeAsync(String data) { 
     // ... do something that takes 300ms .... 
     try { 
      log.debug("Iteration number: " + data + " Thread: " + Thread.currentThread().getName()); 

      Thread.sleep(2000); 
      log.debug("finished"); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

とスケジュールサービス

@Service 
public class MySchedule { 

    @Autowired 
    MyAsyncProcess myAsyncProcess; 

    @Scheduled(cron = "*/8 * * * * *") 
    public void consumeData() { 

     IntStream.range(0,20).forEach(s -> 
      myAsyncProcess.workerBeeAsync(String.valueOf(s))); 

    } 

} 

で設定されていますクラス。

お手伝いをしてください。

1

私はここに記載されたルールに従わないと思われます:http://www.baeldung.com/spring-async。最も顕著なのは、自己の呼び出し:

@Asyncは、2つの制限があります。私はあなたがここにエグゼキュータラウンドExceptionHandlingAsyncTaskExecutorラッパーを削除する以外に何をしたか見ていないよ

it must be applied to public methods only 
self-invocation – calling the async method from within the same class – won’t work 
+0

はい、あなたの結論は正しいです! –