As OpenEJB is deployed into more and more production environments we've been hard at work filling out the system to meet demands. The latest overhaul has been around the @Stateless bean pooling options.

At a high level, the new features provide:

  • Availability: guarantee a minimum number of instance in a pool, from startup and through the entire life of the pool.
  • Shrinking: aggressively shrink pools via an inactive bean timeout and/or gracefully shrink pools via VM garbage collection when memory is needed.
  • Freshness: aggressively flush a pool via the bean's SessionContext and/or gracefully expire, and possibly replace, beans via a max age.

    Using the above features it's possible to build a pool to fit your exact needs. The pool shrinking functionality allows a pool that has reached its maximum size to shrink down over time to its minimum size (which can be zero!) either aggressively or gracefully, keeping resources consumed at a minimum. The freshness functionality allows the entire pool, even the minimum, to be purged and renewed either aggressively or gracefully over time, preventing leaky state from building up over the long life of the pool.

    The new options are: PoolMin, IdleTimeout, PollInterval, MaxAge, ReplaceAged, MaxAgeOffset, and CallbackThreads. Garbage collection functionality is achieved internally through java.lang.SoftReference(s) and nothing is required to enable it, though it can be tuned at the VM level. Pool flushing can be done via the javax.ejb.SessionContext object of Stateless beans which now can be cast to

    All of the above functionality is of course thread-safe. Instances cannot be garbage collected, expired via MaxAge, or flushed while in use. Calling flush() on a "hot" pool will not affect instances in use till they return to the pool. The same applies for any instances that reach their MaxAge while in use -- they are only expired once returned to the pool.

    The above options are properly tuned and balanced as well and will not compete. For example, flushing a pool will not cause any instances created to refill the pool to have the same creation time and therefore expire together in one, very ungraceful, drop. Creation times will be skewed to keep MaxAge expiration spread out. As well MaxAge and IdleTimeout are enforced together such that MaxAge is enforced, instances are transitioned into the "minimum side" of the pool as needed, and the remainder is subject to IdleTimeout. The pool will not timeout a perfectly good instance that could be used to keep the pool at it's minimum.