2

Is there a way to access bean which is defined as @JobScope in partitioned step?

We defined http client bean as @JobScope since it is unique per job but dynamically created and we need it in slave steps to issue post requests. When we autowire everything we get

Error creating bean with name 'scopedTarget.captureErpStockTasklet':
Scope 'step' is not active for the current thread; consider defining a 
scoped proxy for this bean if you intend to refer to it from a singleton;
nested exception is java.lang.IllegalStateException: No context holder 
available for step scope

Here is job configuration class (I have removed everything not needed, left only configuration of partitioned step and Client class which is in @JobScope because on every job run it needs to be job specific:

@Configuration
@EnableBatchProcessing
@ComponentScan(basePackages = {"com.example.importjob"})
public class FrozenFileImportJobConfig {
@Value("${thread.pool:10}")
private int threadPoolSize;
@Value("${partitioner.max.thread.pool:10}")
private int maxThreadPoolSize;
@Value("${grid.size:10}")
private int gridSize;
@Value("${client.url:some_url}")
private int url;
@Value("${client.id:client_id}")
private int clientId;
@Value("${client.secret:secret}")
private int clientSecret;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
 @Autowired
private ErpStockIdPartitioner erpStockIdPartitioner;
@Autowired
private CaptureErpStockTasklet captureErpStockTasklet;
@Bean(destroyMethod = "destroy")
@JobScope
public Client client() {
  return new Client(url, clientId, clientSecret);
}

public ExecutionContextPromotionListener contextPromotionListener() {
  final ExecutionContextPromotionListener executionContextPromotionListener = new ExecutionContextPromotionListener();
  executionContextPromotionListener.setKeys(new String[] {"erp_stock_ids"});
  return executionContextPromotionListener;
}

public Step captureErpStockDBTaskletStep() {
  return stepBuilderFactory.get("captureErpStockDBTaskletStep").tasklet(captureErpStockTasklet).build();
}

@Bean
public ThreadPoolTaskExecutor erpStockIdTaskExecutor() {
  final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
  threadPoolTaskExecutor.setCorePoolSize(threadPoolSize);
  threadPoolTaskExecutor.setMaxPoolSize(maxThreadPoolSize);
  threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
  return threadPoolTaskExecutor;
}
public Step partitioningCaptureStep() {
  return stepBuilderFactory.get("partitioningCaptureStep").partitioner(captureErpStockDBTaskletStep())
.partitioner("erpStockIdPartitioner", erpStockIdPartitioner).taskExecutor(erpStockIdTaskExecutor())
.gridSize(gridSize).allowStartIfComplete(true).build();
}
@Bean
public Job riverIslandFrozenFileImportJob() {
  return jobBuilderFactory.get("riverIslandFrozenFileImportJob").start(partitioningCaptureStep()).build();
}
}

And here is captureErpStockDBTasklet which is invoked as partitioned step from master partitioningCaptureStep:

@Component
@StepScope
public class CaptureErpStockTasklet implements Tasklet {
  private static final Logger LOG = LoggerFactory.getLogger(CaptureErpStockTasklet.class);
  @Value("#{jobParameters[" + FtpJobParameters.ORGANIZATION_ID + "]}")
  private Long organizationId;
  @Autowired
  private ErpStockRepository erpStockRepository;
  @Autowired
  private Client client;
  @Override
  public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception {
    //importing of erp stock from DB, nothing special in that code so removed
     client.captureErpStock(stock);
     LOG.info("[{}] Finished importing ERP {}", organizationId, erpStock);
     return RepeatStatus.FINISHED;
  }
}

When I change in configuration Clinet to be @StepScope it works fine but than I get client created for every step which is not what I want, I want to have one for entire job.

Nenad Bozic
  • 3,724
  • 19
  • 45
  • Can you add the job definition (xml/javaconfig) and the class that uses CaptureErpStockTasklet – Haim Raman Mar 12 '15 at 04:44
  • I added java configuration class and tasklet. As in post when I change client to be `@StepScope` it works fine but that is not what I wanted. – Nenad Bozic Mar 12 '15 at 08:02

1 Answers1

3

I think that this is an issue in spring batch when useing Job Scope beans in a partitioned step.

See: https://jira.spring.io/browse/BATCH-2269 And Multi-threaded acces to Job Scope beans in Spring Batch 3.0

Community
  • 1
  • 1
Haim Raman
  • 11,508
  • 6
  • 44
  • 70