jakartaee / batch

The Jakarta Batch project produces the Batch Specification and API.
https://projects.eclipse.org/projects/ee4j.batch
Apache License 2.0
13 stars 17 forks source link

Define job registration mechanism with Java-defined job (e.g. at app startup?) #177

Open scottkurz opened 3 years ago

scottkurz commented 3 years ago

Though a Java-defined job (as discussed in https://github.com/eclipse-ee4j/batch-api/issues/109 ) could define jobs on a purely dynamic basis, (define then immediately start), it also could be useful to provide a registration mechanism so they could be registered, and then later started by name, e.g. via JobOperator.start(String jobName, ...), (though not necessarily required to close https://github.com/eclipse-ee4j/batch-api/issues/109).

Some ideas around this were discussed in ML thread: https://www.eclipse.org/lists/jakartabatch-dev/msg00147.html.

Since there was clearly some interest in this proposal, I'm opening this issue to track further work and discussion, and adding for now to the 2.1 milestone.

OndroMih commented 3 years ago

I think the same API can be used for both purely dynamic configuration and registration during application startup, if a configuration object is passed to a CDI bean at application startup and could be also passed to a method that defines the job dynamically.

With a CDI bean, a job could be defined with e.g. a CDI event as follows (as described by @rmannibucau here):

void defineBatches(@Observes JobRegistrationCallback cb, JobOperator op, MyService service) {
    cb.defineJob("my-job")
       .batchlet("exec-sql", () -> service.executeBulkQuery().then(service::flush));
}

The CDI event would be fired at application startup, only once. This would be similar as when job is defined in a XML, which is also evaluated at startup.

And the same job definition could be applied on an instance of a JobOperator with a lambda argument as follows:

@Inject JobOperator op;
@Inject MyService service;

op.defineJob( (JobRegistrationCallback cb) -> {
    cb.defineJob("my-job")
       .batchlet("exec-sql", () -> service.executeBulkQuery().then(service::flush));
});

The defineJob method could even return the created Job definition instance that could be referenced to start a job instead of using the job name:

JobDefinition jobdef = op.defineJob( (JobRegistrationCallback cb) -> {
    return cb.defineJob("my-job");  
   // the `return` statement here isn't even necessary,
   // the `defineJob` method would get the definition from `cb` and return it
});
op.start( jobdef, new Properties() );
rmannibucau commented 3 years ago

If you make it a bean instead of an event it will remove the indirection in the API:

void defineBatches(@Observes @Initialized(ApplicationScoped.class) Object startup, JobRegistrationCallback cb /* optionally other services */) {
    cb.defineJob("my-job")
       .batchlet("exec-sql", () -> service.executeBulkQuery().then(service::flush));
}

and

@Inject JobRegistrationCallback cb;
@Inject MyService service;

cb.defineJob("my-job")
       .batchlet("exec-sql", () -> service.executeBulkQuery().then(service::flush));

Then no need to change JobOperator#start method signature since the job is named anyway (required to keep job operator reporting features).

scottkurz commented 2 years ago

Seems we're not going to get to this in 2.1.