我有一个Web应用程序,它从用户那里获取输入并使用它根据调用各种外部Web服务的结果生成报告。
我想跟踪报告生成的进度,能够查看每个步骤的状态,开始时间和停止时间。
我添加了域对象Job
和JobStep
:
@Entity
@Table(name="jobs")
@Data
@EqualsAndHashCode(callSuper=false, of={ "id" })
@ToString()
public class Job extends DomainObject {
@NotNull
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="job_id")
private Set<JobStep> steps = new TreeSet<JobStep>();
protected Job() {/*Hibernate requirement*/}
public Job() {
// Create all the steps in the beginning with the default settings:
// status=waiting, date_time both null.
for (JobStep.Type stepType : JobStep.Type.values()) {
JobStep step = new JobStep(stepType);
steps.add(step);
}
}
public Set<JobStep> getSteps() {
return steps;
}
public void startStep(JobStep.Type stepType)
{
for (JobStep step : steps) {
if (step.getType() == stepType) {
step.start();
return;
}
}
}
public void stopStep(JobStep.Type stepType, JobStep.Status status) {
for (JobStep step : steps) {
if (step.getType() == stepType) {
step.stop(status);
return;
}
}
}
}
@Entity
@Table(name="job_steps")
@Data
@EqualsAndHashCode(callSuper=false, of={ "type", "job" })
@ToString
public class JobStep extends DomainObject implements Comparable<JobStep> {
private static final Logger LOG = LoggerFactory.getLogger(JobStep.class);
public enum Type {
TEST_STEP1,
TEST_STEP2,
TEST_STEP3
}
public enum Status {
WAITING,
RUNNING,
FINISHED,
ERROR
}
@NotNull
@Getter
@Enumerated(EnumType.STRING)
private Type type;
@NotNull
@Setter(AccessLevel.NONE)
@Enumerated(EnumType.STRING)
private Status status = Status.WAITING;
@Setter(AccessLevel.NONE)
private DateTime start = null;
@Setter(AccessLevel.NONE)
private DateTime stop = null;
@ManyToOne
private Job job;
protected JobStep() {/*Hibernate requirement */}
public JobStep(Type type) {
this.type = type;
}
public void start() {
assert(status == Status.WAITING);
status = Status.RUNNING;
start = new DateTime();
}
public void stop(Status newStatus) {
assert(newStatus == Status.FINISHED ||
newStatus == Status.ERROR);
assert(status == Status.RUNNING);
status = newStatus;
stop = new DateTime();
}
@Override
public int compareTo(final JobStep o) {
return getType().compareTo(o.getType());
}
}
使用JobService
类来操纵它们:
@Service
public class JobService {
private static final Logger LOG = LoggerFactory.getLogger(JobService.class);
@Autowired
private JobDAO jobDao;
@Transactional
public void createJob() {
Job job = new Job();
Long id = jobDao.create(job);
LOG.info("Created job: {}", id);
}
@Transactional
public Job getJob(Long id) {
return jobDao.get(id);
}
@Transactional
public void startJobStep(Job job, JobStep.Type stepType) {
LOG.debug("Starting JobStep '{}' for Job {}", stepType, job.getId());
job.startStep(stepType);
}
@Transactional
public void stopJobStep(Job job, JobStep.Type stepType,
JobStep.Status status) {
LOG.debug("Stopping JobStep '{}' for Job {} with status {}", stepType,
job.getId(), status);
job.stopStep(stepType, status);
}
}
所以在开始一个步骤的方法中,我可以写:
class Foo() {
@Autowired
JobService jobService;
public void methodThatStartsAStep(Job job) {
jobService.startJobStep(job, JobStep.Type.TEST_STEP1);
// Implementation here
}
}
我遇到的问题是找到一种方法将Job
实例提供给需要它的方法,以便记录步骤已经开始。
显而易见的解决方案是将Job
作为参数传递(如上所述),但传递Job
并不总是有意义 - 只记录步骤(下面的极端示例) ):
public int multiplySomeNumbers(Job job, int num1, int num2) {
jobService.startJobStep(job, JobStep.Type.TEST_STEP1);
// Implementation here.
}
我对理想的解决方案有两点想法:
Job
对象或id存储在类似全局的范围(例如会话或上下文)中。我尝试在我的@Scope("session")
上使用JobService
,目的是在那里存储Job
个实例,但我不断获得java.lang.IllegalStateException: No thread-bound request found
。我甚至不确定这是否是这种解决方案的正确用例。我的问题是:
Job
或其ID,以便我不必将Job
作为参数添加到方法中? 答案 0 :(得分:0)
您可以将它保存在本地线程中,您可以直接从本地线程访问Object,或者您可以创建自定义Spring范围以获取有关自定义范围http://springindepth.com/book/in-depth-ioc-scope.html的更多信息。您可以在自定义范围中定义作业并将其注入到bean中。
编辑:只有当您的整个流程在单线程中运行并且您的作业步骤是静态的时,您才能按照您提到的流程进行操作。如果您的工作不是静态的(意味着调用外部服务/外部服务的顺序可能会根据输入进行更改),我将实现链责任和命令模式(命令作为实际流程)和链作为您的工作步骤。然后,您可以根据配置跟踪/停止/更改步骤。
答案 1 :(得分:0)
问:问题2,我将走出困境,尽可能广泛地定义这个问题。
您似乎正在重新实现Spring Batch。 Batch广泛支持定义和执行作业,持续工作进度和支持恢复。它还具有记住状态和将状态从一个步骤移动到另一个步骤的背景,面向块的处理,以及通常经过深思熟虑和广泛的基础设施,包括一堆用于常见工作流的读者和编写者。
随意忽略这个答案,我只是想把这个建议扔到那里,以免它让你无所事事。