javaee / ejb-spec

See javax.ejb project for API. Contains legacy issues only.
https://github.com/javaee/javax.ejb
6 stars 1 forks source link

Define standard way to configure where timers are persisted #45

Closed glassfishrobot closed 12 years ago

glassfishrobot commented 12 years ago

Section 18.4.3 of the EJB 3.1 spec defines that timers created by the EJB Timer Service are persistent:

Timers are persistent objects (unless explicitly created as non-persistent timers). In the event of a container crash or container shutdown, any single-event persistent timers that have expired during the intervening time before container restart must cause the corresponding timeout callback method to be invoked upon restart. Any interval persistent timers or schedule based persistent timers that have expired during the intervening time must cause the corresponding timeout callback method to be invoked at least once upon restart.

There is however no notion of where timers are exactly persisted. In practice implementations often use an embedded database for this persistence requirement, which in turn means timers end up being persisted somewhere inside the installation directory of the application server.

This can be undesirable since it means outstanding timers are lost whenever an application is e.g. migrated to another application server, the application server is upgraded, etc. Implementations have recognized this issue and many provide a way to persist timers to a user-specified database.

I would like to propose standardizing this, so EJB applications can be more portable.

For instance:

@Stateless
public class SomeBean {

    @Resource(lookup="java:/myDs")
    private DataSource dataSource;

    @Resource
    private TimerService timerService;

    public void doSchedule() {
        timerService.createSingleActionTimer(new Date(), new TimerConfig("test", dataSource));
    }

    @Timeout
    public void timeout(Timer timer) {

    }

    @Schedule(hour = "*", minute = "*/30", second="0", dataSource="java:/myDs")
    public void scheduled() {

    }
}

In the example above, both the programmatic and automatic timers would be persisted to the data source located at "java:/myDs" in a table with a default name defined by the spec. Optionally the user should be able to specify a table name, e.g.:

@Schedule(hour = "*", minute = "*/30", second="0", dataSource="java:/myDs", table="EJB_TIMERS")
public void scheduled() {

}

The user should not need to know anything about the table structure in advance. If the table doesn't exist yet, the container should create it with the required columns.

glassfishrobot commented 12 years ago

Reported by @arjantijms

glassfishrobot commented 12 years ago

abien said: +1 A very good point. It would also make the monitoring of timers easier. Right now you have to search in container-specific configuration to find the corresponding datasource.

glassfishrobot commented 12 years ago

wolfc said: Maybe not just where, but also how timers are persisted?

http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/projects/ejb3/trunk/timerservice-mk2/src/main/java/org/jboss/ejb3/timerservice/mk2/persistence/TimerEntity.java?revision=84539&view=markup

glassfishrobot commented 12 years ago

mvatkina said: The timer service cannot be required to store each timer in its own place, so specifying those details on the createTimer() call (or @Schedule annotation) can be misleading. On the other hand, if anybody is interested in writing a proposal how to specify the timer service details on the per-application basis (so that the application fails deployment if the resource doesn't match or can't be supported by the EJB container provider), please add it here or send to the EG mail list.

glassfishrobot commented 12 years ago

@arjantijms said:

The timer service cannot be required to store each timer in its own place

That's an important limitation to be aware of and the syntax I proposed above wouldn't make much sense then.

One proposal that quickly comes to mind is defining this globally in ejb-jar.xml in case of a .war or (EJB) .jar deployment, and application.xml in case of an .ear deployment. Anticipating on #2, an independent new file like e.g, timer.xml might be an option as well (much like JPA has its own persistence.xml).

The syntax of such XML files could be fairly straight-forward; a parent timer-service element, with attributes for the dataSource, table, etc. E.g.

<timer-service>
    <data-source>java:/myDs</data-source>
    <table>EJB_TIMERS</table>
</timer-service>

A programmatic configuration could possibly be realized via a CDI factory method for some kind of timer configuration type. E.g.

@Singleton
public class MyTimerConfigurationBean {

    @Resource(lookup="java:/myDs")
    private DataSource dataSource;

    @Produces
    public TimerServiceConfig getConfig() {
        return new TimerServiceConfig()
             .withDataSource(dataSource)
             .withTable("EJB_TIMERS");
    }

}
glassfishrobot commented 12 years ago

mvatkina said: @Produces won't work without CDI... so we would need an EJB-specific annotation (but that would eliminate the need for an injected DataSource...

glassfishrobot commented 12 years ago

@arjantijms said:

@Produces won't work without CDI...

That's indeed true, so if something like this would be considered than a consequence would be a CDI dependency for EJB. The question is whether this is really something to avoid? I noticed at least one other specification for Java EE 7 now also has a CDI dependency: JSF 2.2.

If it's done programmatically via an EJB specific annotation, it could perhaps still be done with an injected DataSource or in generally a DataSource a user gets from somewhere. E.g.

@Singleton
public class MyTimerConfigurationBean {

    @TimerConfig
    public TimerServiceConfig getConfig() {
        DataSource dataSource = ... // Get in some way from some place
        return new TimerServiceConfig()
             .withDataSource(dataSource)
             .withTable("EJB_TIMERS");
    }
}

or alternatively;

@Singleton
public class MyTimerConfigurationBean {

    @TimerConfig
    public TimerServiceConfig getConfig() {
        return new TimerServiceConfig()
             .withDataSourceLookup("java:/myDs")
             .withTable("EJB_TIMERS");
    }
}
glassfishrobot commented 12 years ago

petermuir said: Like Arjan says, just define the TimerServiceConfig and a way to register it (even programmatically) and we can add the @Produces integration in the CDI spec. e.g.

EJBContext.registerTimer(TimerServiceConfig);

glassfishrobot commented 12 years ago

mvatkina said: The datasource and the table are the information that the EJB container needs before starting the timer service, so registering it when the bean is already running, is too late. Will a class-level annotation work?

glassfishrobot commented 12 years ago

@arjantijms said:

Will a class-level annotation work?

A class-level annotation would surely work as an alternative for the XML configuration. Following the Java EE tradition of having nearly all XML configuration also expressible via annotations this would surely be a no-brainer to specify.

However, a class-level annotation is not really an alternative for a programmatic solution. With a programmatic solution, the user can via custom logic and rules determine what the outcome of each parameter is to be. This obviously is not possible with either an annotation or XML. (compare this with registering a Servlet, which can be done in XML, via an annotation or programmatically)

Should programmatic configuration prove to be too difficult to specify then just having static configuration will definitely work as well. The proposal doesn't absolutely require it, but it would be nice to have.

The datasource and the table are the information that the EJB container needs before starting the timer service, so registering it when the bean is already running, is too late.

That seems logical indeed. What I was aiming for with the tt>@Produces</tt (or EJB specific annotation) is that the EJB container would look for a TimerServiceConfig producer being available. If it is, obtain an instance from this producer before starting the timer service and use this instance to configure the service.

Thus, timer configuration would not be possible in arbitrary methods (including @PostConstruct in @Singletone @Startup beans). It would only be possible in the special method that's called by the EJB container. This special method is marked at such by an annotation. CDI would seem convenient for this since it already has this concept of the one and only producer for a type.

glassfishrobot commented 12 years ago

mvatkina said: Will it be simpler to define a new deployment descriptor element similar to the above, but using lookup instead of the - the latter is (and can be) used to define a resource (like @DataSourceDefinition), not to reference one:

<timer-service>
    <lookup>java:global/jdbc/myDs</data-source>
    <table>EJB_TIMERS</table>
</timer-service>

With a matching class-level annotation

@TimerServiceConfig(lookup="java:global/jdbc/myDs", table="EJB_TIMERS")

This will also allow to define the resource for the timer service via or @DataSourceDefinition.

The rule that the application deployment will fail if a resource cannot be created or if the timer service has been already configured to use a different resource, still stands.

glassfishrobot commented 12 years ago

@arjantijms said: With only "lookup", maybe there will be some confusion about what's being looked-up? I can imagine people thinking it would be a reference to a timer-service stored in JNDI, instead of a data-source used by the timer-service.

What about the following?

<timer-service>
    <data-source-lookup>java:global/jdbc/myDs</data-source-lookup>
    <table>EJB_TIMERS</table>
</timer-service>
glassfishrobot commented 12 years ago

mvatkina said: Yes. This is more precise.

glassfishrobot commented 12 years ago

@arjantijms said: Concerning Jeremy Bauer's comment (http://java.net/projects/ejb-spec/lists/jsr345-experts/archive/2012-07/message/37)::)

This item couples the timer service to a specific persistence mechanism (JDBC data sources) and further, assumes a single table will be used. Even though most vendors likely use JDBC+RDB for persistent timers, I don't think this should be required by the specification.

Isn't the proposal about using JDBC data-sources only applicable when the user explicitly asks for this? If the user hasn't configured anything the vendor would be free to use any mechanism that seems fit to do the job.

glassfishrobot commented 12 years ago

mvatkina said: Jeremy's comment was that the EJB containers should not be required to store timers in a way they did not intend to.

glassfishrobot commented 12 years ago

mvatkina said: This proposal was not accepted by the EG - see thread http://java.net/projects/ejb-spec/lists/jsr345-experts/archive/2012-07/message/42

glassfishrobot commented 12 years ago

@arjantijms said:

Jeremy's comment was that the EJB containers should not be required to store timers in a way they did not intend to.

Isn't that the entire idea behind standardization? Vendors all have individual ideas regarding how to do things, and that's fine of course. But there are also requirements to have things working on different implementations (i.e. the entire "portability" argument).

Those two concerns don't have to bite each other. If for example IBM would think timers are better off being stored in some optimized local file container, they can still advise their customers to use this. But additionally, they would provide the JDBC based standard version, for customers needing portability.

It's IMHO not much different as with several other standard facilities. Java EE defines a standardized data source definition, but vendors like JBoss still actively try to persuade their customers to use their proprietary method instead. It's up to the customer to decide what's more important to them.

This proposal was not accepted by the EG

Really sad to hear that. I think the ongoing popularity of things like Quartz clearly show there's a demand for this kind of functionality. Reading the thread I also don't see a lot of people really being against it. Stefan Heidt for example merely seemed to mention it should not be an optional technology, as that would indeed defeat its main purpose.

glassfishrobot commented 12 years ago

mvatkina said: Unfortunately nobody in the EG voiced their opinion in favor of this standardization.

glassfishrobot commented 12 years ago

Was assigned to mvatkina

glassfishrobot commented 7 years ago

This issue was imported from java.net JIRA EJB_SPEC-45

glassfishrobot commented 12 years ago

Marked as won't fix on Monday, July 30th 2012, 11:09:58 am