Java EE 7 - will new threads join ongoing transaction and commit/rollback at end of starting thread? - java-ee-7

doStuff(tasks);
...
#Transactional
public void doStuff(List<Task> tasks) {
// run async
for(... task ...)
new Thread(() -> localServiceB.handle(task)).start();
}
....
#Transactional
public class LocalServiceB {
public void handle() ....
}
? when will the outer transaction end?
? cand "handle() join the transaction from "doStuff"?
? how can a single transaction span the doStuff and all forked threads until the last "handle" has finished, even if "doStuff" has finished already. (hint: I prefer doStuff NOT to wait for the threads)

All tasks run without an explicit transaction (they do not enlist in the application component's transaction).
https://docs.oracle.com/javaee/7/api/javax/enterprise/concurrent/ManagedExecutorService.html

Related

handle separate transaction in java batch (JSR-352)

I'm using jberet implementation of JSR 352 java batch specs.
Actually I need a separate transaction for doing a singular update, something like this:
class MyItemWriter implements ItemWriter
#Inject
UserTransaction transaction
void resetLastProductsUpdateDate(String uidCli) throws BusinessException {
try {
if (transaction.getStatus() != Status.STATUS_ACTIVE) {
transaction.begin();
}
final Customer customer = dao.findById(id);
customer.setLastUpdate(null);
customer.persist(cliente);
transaction.commit();
} catch (RollbackException | HeuristicMixedException | HeuristicRollbackException | SystemException | NotSupportedException e) {
logger.error("error while updating user products last update");
throw new BusinessException();
}
}
I first tried marking resetLastProductsUpdateDate methoad as #Transactional(REQUIRES_NEW), however it didn't worked.
My question is:
Is there any more elegant way to achieve this singular transaction without manually handle of transaction?
While does UserTransation works, EntityManager.transaction doesn't. I don't get it why.
Class below, which is injected from a Batchlet, works properly; Why I can't get to make work the #Transactional annotation on resetLastProductsUpdateDate method instead?
public class DynamicQueryDAO {
#Inject
EntityManager entityManager;
#Inject
private Logger logger;
#Transactional(Transactional.TxType.REQUIRED)
public void executeQuery(String query) {
logger.info("executing query: {}", query);
final int output = entityManager.createNativeQuery(query).executeUpdate();
logger.info("rows updated: {}", output);
}
}
EDIT
Actually I guess neither usertransaction is a good solution, because it affects entire itemwriter transaction management. Still Don't know how to deal with transaction isolation :(
In general the batch application should avoid directly handling transaction. You can have your batch component to throw some business exceptions upon certain conditions, and configure your job.xml to trigger retry upon this business exception. During retry, each individual data will be processed and committed in its own chunk.

Concurrent threads in GemFire CacheWriter

We are currently using Cassandra as NoSQL Database and GemFire as In memory Database. We have been using the GemFire CacheWriter to insert the records in Cassandra. I would like your feedback on whether it’s a good engineering practice to use Concurrent threads in CacheWriter to insert/Update records. Your feedback on this would be appreciated.
public class GenericWriter<K, V> extends CacheWriterAdapter<K, V> implements Declarable {
private static Logger log = LoggerFactory.getLogger(GenericWriter.class);
#Autowired
private CassandraOperations cassandraOperations;
ExecutorService executor = null;
#Override
public void beforeCreate(EntryEvent<K, V> e) {
executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
if (eventOperation.equals("CREATE") || eventOperation.equalsIgnoreCase("PUTALL_CREATE")) {
try {
cassandraOperations.insert(e.getNewValue());
} catch (CassandraConnectionFailureException | CassandraWriteTimeoutException
| CassandraInternalException cassException) {
} catch (Exception ex) {
log.error("Exception in GenericCacheWriter->" + ExceptionUtils.getStackTrace(ex));
throw ex;
}
}
});
executor.shutdown();
}
#Override
public void init(Properties arg0) {
// TODO Auto-generated method stub
}
}
The CacheWriter handler is called synchronously, so the application does not continue until the handler returns. Therefore, is not recommended to execute long-running operations inside this listener. If a long-running operation is needed, consider processing the operation asynchronously through an AsyncEventListener instead.
Using an ExecutorService to delegate the execution to a different thread is possible but it is an anti-pattern, as it no longer implements the fail-fast property, and the handling of the event is no longer synchronous, so its timing would not be guaranteed relative to the application's completion of the event.
You can read more about this topic in the Geode Wiki, specifically in CacheWrite and CacheListener Best Practices.
Hope this helps.
Best regards.
Yes, it's a fine pattern but remove the Executor and partition your data such that all updates into GemFire go to one and only one node. Partition Cassandra the same way. Put a write lock around the Cassandra update. Use this only when your throughput is low.
If you need high throughput, use the AsyncEventListener and guarantee eventual consistency to your users. If you must use Executors in the AEL, use them in a way so as to throw an exception in the main thread. If the update fails after a number of tries, you write the failed entry to a different region with an expiration of a few seconds or a minute. When that expires, retry the operation. Keep doing this until the succeeds and then and only then, delete the expired entry.
You will need to track version numbers and what you are updating watching old values/ new values if order of updates is important to you or not.

How to rollback nHibernate transaction when an exception occurs during request having Ninject for managing sessions?

I use nHibernate for ORM and Ninject for IoC.
I create nHibernate sessions per some custom scope (which you can assume is per request).
I begin the transaction onActivation.
I commit the transaction onDeactivation.
The problem is that if an exception happens during the request I want to rollback the transaction rather than committing it. Any idea how to detect (in a clean way, most probably using Ninject Context) that an exception has happened?
Note: I am not concerned about the exceptions that can happen on commit which I can catch in the following code and role back easily.
protected void BindWithSessionWrapper<T>(Func<IContext, T> creationFunc) where T : ISessionWrapper
{
Bind<T>().ToMethod(creationFunc)
.InScope(x => new NinjectCustomScope()) // work in progress !!!
.OnActivation(t => t.Session.BeginTransaction(IsolationLevel.ReadCommitted))
.OnDeactivation((c, t) =>
{
t.Session.Transaction.Commit();
t.Session.Dispose();
});
}
Update:
I followed the suggestion by #BatteryBackupUnit.
So I added the following to the Error EventHandler:
Error += (s, e) =>
{
HttpContext.Current.Items["ErrorRaised"] = true;
};
And I modified the OnDeactivation to look like this:
OnDeactivation(t =>
{
if ((bool?)HttpContext.Current.Items["ErrorRaised"] == true)
t.Session.Transaction.Rollback();
else
t.Session.Transaction.Commit();
t.Session.Dispose();
});
It works fine, but that would be better if Ninject would take care of this by setting a flag in the Context if an exception happened :)
How about implementing an IHTTPModule and subscribing to the Error event?
Like described here
In the Error event handler, use System.Web.Mvc.DependencyResolver.Current.GetService(typeof (ISession)) to retrieve the current session and rollback the transaction.
Note, however, that in case the request did not use a session, this will create one, which is quite superfluous.
You might do something like checking whether a transaction was started and only then rolling it back. But you'd still create a session unnecessarily.
You could further improve that by using the Error event handler to set a flag on HttpContext.Current.Items, like
HttpContext.Current.Items["RollbackTransaction"] = true;
and then use it in the OnDeactivation of the session like:
.OnDeactivation((c, t) =>
{
if(HttpContext.Current.Items.Contains("RollbackTransaction"])
{
t.Session.Transaction.Rollback();
}
else
{
t.Session.Transaction.Commit();
}
t.Session.Dispose();
});
Please note that HttpContext is thread local, that means when you switch threads it may be null or -worst case - it might even be another HttpContext.
Please also note that i was unable to try it out so it may not work. Feedback appreciated.
Passing the state through HttpContext is not acceptable to me for 2 reasons.
HttpContext issue: https://stackoverflow.com/a/12219078/656430)
Passing state seems like passing a global state (https://softwareengineering.stackexchange.com/questions/148108/why-is-global-state-so-evil)
After a lot of trial and error, I think this should be one solution:
Assuming we are working on WebApi project, having rollback transaction for all actions once hit exception, with Ninject:
install Ninject.Extension.Factory (https://www.nuget.org/packages/Ninject.Extensions.Factory/), this is very important step as to inject ISession in request scope into filters.
use the following configuration for binding ISessionFactory and ISession (I made use of this example: Need a simple example of using nhibernate + unit of work + repository pattern + service layer + ninject), plus ISessionInRequestScopeFactory
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>()
.ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession())
.InRequestScope(); // notice that we don't need to call `BeginTransaction` at this moment
Bind<ISessionInRequestScopeFactory>().ToFactory(); // you don't need to make your implementation, the Ninject.Extension.Factory extension will help you so.
the code for interface ISessionInRequestScopeFactory:
public interface ISessionInRequestScopeFactory
{
ISession CreateSessionInRequestScope(); // return ISession in the request scope
}
Make use of ninject filter injection to add Transaction behaviour to every action (https://github.com/ninject/Ninject.Web.WebApi/wiki/Dependency-injection-for-filters):
Kernel.BindHttpFilter<ApiTransactionFilter>(System.Web.Http.Filters.FilterScope.Action)
.WhenControllerHas<ApiTransactionAttribute>();
add [ApiTransaction] attribute into controller:
[ApiTransaction]
public class YourApiController{ /* ... */}
So we are now binding the ApiTransactionFilter into YourApiController which are having [ApiTransaction] Attribute
Inside ApiTransactionFilter, you should extends AbstractActionFilter and inject the factory ISessionInRequestScopeFactory for getting the correct request scope session:
public class ApiTransactionFilter : AbstractActionFilter{
private readonly ISessionInRequestScopeFactory factory;
public ApiTransactionFilter(ISessionInRequestScopeFactory factory){
this.factory = factory;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
session.BeginTransaction(); // session can begin transaction here ...
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
if (actionExecutedContext.Exception == null) // NO EXCEPTION!
{
session.Transaction.Commit();// session commit here ... may be you like to have try catch here
}
else
{
session.Transaction.Rollback(); // session rollback here ...
}
base.OnActionExecuted(actionExecutedContext);
}
}

StackExchange.Redis transaction methods freezes

I have this code to add object and index field in Stackexchange.Redis.
All methods in transaction freeze thread. Why ?
var transaction = Database.CreateTransaction();
//this line freeze thread. WHY ?
await transaction.StringSetAsync(KeyProvider.GetForID(obj.ID), PreSaveObject(obj));
await transaction.HashSetAsync(emailKey, new[] { new HashEntry(obj.Email, Convert.ToString(obj.ID)) });
return await transaction.ExecuteAsync();
Commands executed inside a transaction do not return results until after you execute the transaction. This is simply a feature of how transactions work in Redis. At the moment you are awaiting something that hasn't even been sent yet (transactions are buffered locally until executed) - but even if it had been sent: results simply aren't available until the transaction completes.
If you want the result, you should store (not await) the task, and await it after the execute:
var fooTask = tran.SomeCommandAsync(...);
if(await tran.ExecuteAsync()) {
var foo = await fooTask;
}
Note that this is cheaper than it looks: when the transaction executes, the nested tasks get their results at the same time - and await handles that scenario efficiently.
Marc's answer works, but in my case it caused a decent amount of code bloat (and it's easy to forget to do it this way), so I came up with an abstraction that sort of enforces the pattern.
Here's how you use it:
await db.TransactAsync(commands => commands
.Enqueue(tran => tran.SomeCommandAsync(...))
.Enqueue(tran => tran.SomeCommandAsync(...))
.Enqueue(tran => tran.SomeCommandAsync(...)));
Here's the implementation:
public static class RedisExtensions
{
public static async Task TransactAsync(this IDatabase db, Action<RedisCommandQueue> addCommands)
{
var tran = db.CreateTransaction();
var q = new RedisCommandQueue(tran);
addCommands(q);
if (await tran.ExecuteAsync())
await q.CompleteAsync();
}
}
public class RedisCommandQueue
{
private readonly ITransaction _tran;
private readonly IList<Task> _tasks = new List<Task>();
public RedisCommandQueue Enqueue(Func<ITransaction, Task> cmd)
{
_tasks.Add(cmd(_tran));
return this;
}
internal RedisCommandQueue(ITransaction tran) => _tran = tran;
internal Task CompleteAsync() => Task.WhenAll(_tasks);
}
One caveat: This doesn't provide an easy way to get at the result of any of the commands. In my case (and the OP's) that's ok - I'm always using transactions for a series of writes. I found this really helped trim down my code, and by only exposing tran inside Enqueue (which requires you to return a Task), I'm less likely to "forget" that I shouldn't be awaiting those commands at the time I call them.
I and our team were bitten by this issue several times, so I created a simple Roslyn analyzer to spot such problems.
https://github.com/olsh/stack-exchange-redis-analyzer

OracleConnection does not support parallel transactions

I'm working with Oracle 11g database and ASP.NET MVC 4 using Enterprise library. I use Transactions on my commands just to be safe if case of any exceptions. I've a main method with BeginTransaction() which calls other methods (Lets call it child method) that contain Begin and Commit Transaction methods.
I'm getting "OracleConnection does not support parallel transactions." exception when I am executing BeginTransaction() method in child method.
Any help on this.
Try to use TransactionScope instead of BeginTransaction method. It supports distributed nested transactions therefore it should help.
void RootMethod()
{
using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
SomeMethod();
scope.Complete();
}
}
void SomeMethod()
{
using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
scope.Complete();
}
}