forked from Archives/Athou_commafeed
run post login activities in a new transaction to avoid database locks
This commit is contained in:
@@ -15,39 +15,40 @@ public class UnitOfWork {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T call(SessionFactory sessionFactory, SessionRunnerReturningValue<T> sessionRunner) {
|
public static <T> T call(SessionFactory sessionFactory, SessionRunnerReturningValue<T> sessionRunner) {
|
||||||
final Session session = sessionFactory.openSession();
|
|
||||||
if (ManagedSessionContext.hasBind(sessionFactory)) {
|
|
||||||
throw new IllegalStateException("Already in a unit of work!");
|
|
||||||
}
|
|
||||||
T t = null;
|
T t = null;
|
||||||
try {
|
|
||||||
ManagedSessionContext.bind(session);
|
boolean sessionAlreadyBound = ManagedSessionContext.hasBind(sessionFactory);
|
||||||
session.beginTransaction();
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
if (!sessionAlreadyBound) {
|
||||||
|
ManagedSessionContext.bind(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transaction tx = session.beginTransaction();
|
||||||
try {
|
try {
|
||||||
t = sessionRunner.runInSession();
|
t = sessionRunner.runInSession();
|
||||||
commitTransaction(session);
|
commitTransaction(tx);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
rollbackTransaction(session);
|
rollbackTransaction(tx);
|
||||||
UnitOfWork.<RuntimeException> rethrow(e);
|
UnitOfWork.rethrow(e);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
if (!sessionAlreadyBound) {
|
||||||
ManagedSessionContext.unbind(sessionFactory);
|
ManagedSessionContext.unbind(sessionFactory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void rollbackTransaction(Session session) {
|
private static void rollbackTransaction(Transaction tx) {
|
||||||
final Transaction txn = session.getTransaction();
|
if (tx != null && tx.isActive()) {
|
||||||
if (txn != null && txn.isActive()) {
|
tx.rollback();
|
||||||
txn.rollback();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void commitTransaction(Session session) {
|
private static void commitTransaction(Transaction tx) {
|
||||||
final Transaction txn = session.getTransaction();
|
if (tx != null && tx.isActive()) {
|
||||||
if (txn != null && txn.isActive()) {
|
tx.commit();
|
||||||
txn.commit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import javax.inject.Inject;
|
|||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
import com.commafeed.backend.dao.UserDAO;
|
import com.commafeed.backend.dao.UserDAO;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
import com.commafeed.backend.service.FeedSubscriptionService;
|
import com.commafeed.backend.service.FeedSubscriptionService;
|
||||||
@@ -20,6 +22,7 @@ public class PostLoginActivities {
|
|||||||
|
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
private final FeedSubscriptionService feedSubscriptionService;
|
private final FeedSubscriptionService feedSubscriptionService;
|
||||||
|
private final SessionFactory sessionFactory;
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
|
|
||||||
public void executeFor(User user) {
|
public void executeFor(User user) {
|
||||||
@@ -27,19 +30,26 @@ public class PostLoginActivities {
|
|||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
|
||||||
boolean saveUser = false;
|
boolean saveUser = false;
|
||||||
|
|
||||||
// only update lastLogin field every hour in order to not
|
// only update lastLogin field every hour in order to not
|
||||||
// invalidate the cache every time someone logs in
|
// invalidate the cache every time someone logs in
|
||||||
if (lastLogin == null || lastLogin.before(DateUtils.addHours(now, -1))) {
|
if (lastLogin == null || lastLogin.before(DateUtils.addHours(now, -1))) {
|
||||||
user.setLastLogin(now);
|
user.setLastLogin(now);
|
||||||
saveUser = true;
|
saveUser = true;
|
||||||
}
|
}
|
||||||
if (config.getApplicationSettings().getHeavyLoad() && user.shouldRefreshFeedsAt(now)) {
|
|
||||||
|
if (Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad()) && user.shouldRefreshFeedsAt(now)) {
|
||||||
feedSubscriptionService.refreshAll(user);
|
feedSubscriptionService.refreshAll(user);
|
||||||
user.setLastFullRefresh(now);
|
user.setLastFullRefresh(now);
|
||||||
saveUser = true;
|
saveUser = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saveUser) {
|
if (saveUser) {
|
||||||
userDAO.saveOrUpdate(user);
|
// Post login activites are susceptible to run for any webservice call.
|
||||||
|
// We update the user in a new transaction to update the user immediately.
|
||||||
|
// If we didn't and the webservice call takes time, subsequent webservice calls would have to wait for the first call to
|
||||||
|
// finish even if they didn't use the same database tables, because they updated the user too.
|
||||||
|
UnitOfWork.run(sessionFactory, () -> userDAO.saveOrUpdate(user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user