繁体   English   中英

Spring批处理作业状态配置

[英]Spring batch job status configuration

我希望能够在作者引发异常时将步骤和作业状态设置为失败。 在进行了一些调试并检查了Spring批处理源代码之后,我注意到RepeatTemplate配置了SimpleRetryExceptionHandler ,该处理程序将BatchRuntimeException视为致命异常,因此将作业状态设置为FAILED,因此我尝试将代码包装在我的编写器中-catch,将RuntimeException包装在BatchRuntimeException ,现在,根据需要,作业和步骤的状态设置为FAILED。 我不确定这是否是正确的方法,因为我在任何地方都找不到文档,并且BatchRuntimeException的文档也没有任何说明。 因此,问题将是:这是正确的方法吗?

我想到的另一件事是,如果写入失败,则使作业失败是否有意义,但考虑到我的用例,我认为这是有意义的,就像这样:使用流读取器(配置查询以针对数据库运行),然后使用流编写器通过电子邮件或http发送这些条目(检索配置,以流打开方法在其中发送项目)。 如果一切成功,则使用状态SENT更新数据库条目,如果在doOpen / open / write方法期间发生错误,则调用StepExecutionListener来发送作业失败的通知电子邮件。 这就是为什么我需要将作业状态设置为FAILED的原因之一,以便正确执行StepExecutionListener (检查ExitCode是否为FAILED)。 第二个原因是我想使用spring Batch Admin应用程序来管理作业,并且如果该作业显示为COMPLETED,尽管编写失败,但由于该作业的重点是发送项目,因此这似乎具有误导性。如果更改了配置(例如,正确配置了to电子邮件地址),则该作业失败后可以重新启动。

另外,如果写调用失败,则数据库中的条目应将其状态更新为FAILED,我计划在新事务中的ItemWriteListener的onWriteError中执行ItemWriteListener ,因为当前事务将被回滚。

我发布了所有这些详细说明,只是为了确保我不会在这里违反框架的意图,而是试图将作者的工作状态设置为FAILED。

期待您对此的想法。

问候,克里斯蒂

PS:作业配置如下:

<batch:job id="job">
    <batch:step id="step">
        <batch:tasklet>
            <batch:chunk reader="reader" writer="writer" reader-transactional-queue="true" commit-interval="#{properties['export.page.size']}"/>
        </batch:tasklet>
        <batch:listeners>
            <batch:listener ref="failedStepListener"/>
        </batch:listeners>
    </batch:step>
</batch:job>

稍后编辑:读取器和写入器配置如下:

<bean name="reader" class="...LeadsReader" scope="step">
    <property name="campaignId" value="#{jobParameters[campaignId]}" />
    <property name="partnerId" value="#{jobParameters[partnerId]}" />
    <property name="from" value="#{jobParameters[from]}" />
    <property name="to" value="#{jobParameters[to]}" />
    <property name="saveState" value="false" /> <!-- we use a database flag to indicate processed records -->
</bean>

<bean name="writer" class="...LeadsItemWriter"  scope="step">
    <property name="campaignId" value="#{jobParameters[campaignId]}" />
</bean>

编写者的代码是:

public class LeadsItemWriter extends AbstractItemStreamItemWriter<Object[]> {

//fields and setters omitted

public LeadsItemWriter() {
    setName(ClassUtils.getShortName(LeadsItemWriter.class));
}

@Override
public void open(ExecutionContext executionContext) {
    super.open(executionContext);
    PartnerCommunicationDTO partnerCommunicationDTO = this.leadableService.getByCampaignId(this.campaignId)
            .getPartnerCommDTO();
    this.transportConfig = partnerCommunicationDTO != null ? partnerCommunicationDTO.getTransportConfig() : null;
    this.encoding = partnerCommunicationDTO != null ? partnerCommunicationDTO.getEnconding() : null;
    if (this.transportConfig == null) {
        throw new ItemStreamException ("Failed to retrieve the transport configuration for campaign id: "
                + this.campaignId);
    }
    PageRequestDTO pageRequestDTO = this.pageRequestMapper.map(partnerCommunicationDTO);
    if (pageRequestDTO == null) {
        throw new ItemStreamException("Wrong transport mapping configured for campaign id: " + this.campaignId);
    }
    this.columnNames = new ArrayList<>();
    for (LeadColumnDTO leadColumnDTO : pageRequestDTO.getColumns()) {
        this.columnNames.add(leadColumnDTO.getName());
    }
}

@Override
public void write(List<? extends Object[]> items) throws Exception {
    try {
        if (this.transportConfig.getTransportType() == TransportConfigEnum.EMAIL) {
            this.leadExporterService.sendLeads(items, this.columnNames, this.transportConfig, this.encoding);
        } else {
            for (Object[] lead : items) {
                this.leadExporterService.sendLead(lead, this.columnNames, this.transportConfig, this.encoding);
            }
        }
    } catch (RuntimeException e) {
        LOGGER.error("Encountered exception while sending leads.", e);
        //wrap exception so that the job fails and the notification listener gets called
        throw new BatchRuntimeException(e);
    }

}

}

读者的代码:

public class LeadsReader extends AbstractPagingItemReader<Object[]> {

//fields and setters omitted

public LeadsReader() {
    setName(ClassUtils.getShortName(LeadsReader.class));
}

@Override
protected void doOpen() throws Exception {
    this.pageRequestDTO = this.pageRequestMapper.map(this.leadableService.getByCampaignId(this.campaignId)
            .getPartnerCommDTO());
    if (pageRequestDTO == null) {
        throw new ItemStreamException("Wrong transport mapping configured for campaign id: " + this.campaignId);
    }
    this.timeInterval = new LeadTimeIntervalDTO(this.from != null ? of(this.from,
            LeadQueryFilterParam.Comparison.GT) : null,
            this.to != null ? of(this.to, LeadQueryFilterParam.Comparison.LE) : null);

    super.doOpen();
}

private LeadFilterDTO of(Date date, LeadQueryFilterParam.Comparison comparison) {
    LeadFilterDTO filterDTO = new LeadFilterDTO();
    filterDTO.setColumn(CREATION_DATE);
    filterDTO.setSqlType(DATE);
    filterDTO.setComparison(comparison.name());
    filterDTO.setValue(DateUtil.format(date, Validator.DATE_FORMAT));
    return filterDTO;
}

@Override
protected void doReadPage() {
    if (results == null) {
        results = new CopyOnWriteArrayList<>();
    } else {
        results.clear();
    }
    if (this.pageRequestDTO != null) {
        results.addAll(LeadsReader.this.leadStorageService.listLeads(
                LeadsReader.this.pageRequestDTO.getColumns(),
                LeadsReader.this.getFilters(),
                LeadsReader.this.pageRequestDTO.getQueryOrderByParams(),
                LeadsReader.this.pageRequestDTO.isUniqueByEmail(), LeadsReader.this.timeInterval,
                (long) getPage() + 1, (long) getPageSize()).getExportedLeadsRows());
    }

}

private List<LeadFilterDTO> getFilters() {

    List<LeadFilterDTO> filtersList = new ArrayList<>();

    LeadFilterDTO campaignFilter = new LeadFilterDTO();
    campaignFilter.setColumn(CAMPAIGN_ID);
    campaignFilter.setValue(Long.toString(campaignId));
    campaignFilter.setSqlType(BIGINTEGER);
    filtersList.add(campaignFilter);

    LeadFilterDTO partnerFilter = new LeadFilterDTO();
    partnerFilter.setColumn(PARTNER_ID);
    partnerFilter.setValue(Long.toString(partnerId));
    partnerFilter.setSqlType(BIGINTEGER);
    filtersList.add(partnerFilter);

    LeadFilterDTO statusFilter = new LeadFilterDTO();
    statusFilter.setColumn(STATUS);
    statusFilter.setValue("VALID");
    statusFilter.setSqlType(CHAR);

    filtersList.add(statusFilter);

    return filtersList;
}

@Override
protected void doJumpToPage(int itemIndex) {
}

}

如果一个异常是由框架(特别是一个内部的组件抛出ItemReaderItemProcessorItemWriter ,或者Tasklet )并没有被捕获,如失败,没有你做任何额外的执行元件步骤将被标记。 如果某个步骤失败,则该作业也会被标记为失败(这是允许重新启动该作业的原因)。

简而言之,当引发异常时,您无需执行任何其他操作即可使工作失败。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM