Getting LazyInitializationException "could not initialize proxy - no Session" when running a transaction in a background thread - multithreading

I have a strange problem:
Say I have two Entity classes, e.g. Container and ContainedObject. Container has a #OneToMany relationship to ContainedObject.
When getting the contained objects directly, everything works fine, but when running from a background thread, I get "could not initialize proxy - no Session".
Example:
#Component
public class Something {
#Autowired
private ContainerRepository _repo;
public void doInForeground() {
Container container = _repo.findOne(42L); // suppose 42 exists
container.getContainedObjects().size(); // succeeds
}
public void submitToBackground() {
CompletableFuture<Void> f = CompletableFuture.supplyAsync(() -> doInBackground());
}
private Void doInBackground() {
Container container = _repo.findOne(42L);
container.getContainedObjects().size(); // throws LazyInitializationException
}
}
The ContainerRepository is a PagingAndSortingRepository. Running doInForegroundsucceeds, but submitToBackground throws the well-known LazyInitializationException "could not initialize proxy - no Session"
It seems as if no transaction is started or it is closed too fast. Annotating any of the methods with #Transactional does not help either.
Is it simply not possible to use Spring-JPA in background threads or is any additional magic needed?

1) You need a readOnly transaction to get lazy collections.
2) I suppose that #Transactional doesn't work on your local methods because when you call a local method you call the implementation directly, not a proxy object created by Spring.
If it's the case there are at least 2 choices:
1) Switch to Aspectj
<tx:annotation-driven mode="aspectj" proxy-target-class="true"/>
2) Create a transaction manually using TransactionTemplate inside doInForeground():
http://simplespringtutorial.com/springProgrammaticTransactions.html

Related

Issue using #Transactional annotation above integration test class for multithreading environment

When I run the integration test for code which calls JPA repository within a new thread, I'm getting data that was populated during starting PostgreSQLContainer and I can't receive data from the script above class test( #Sql(scripts ="data.sql").
But when I remove #Transactional annotation above the test I can get data both from SQL script from test and test container.
My question is it possible to get data in a multithreading environment from test script without removing #Transactional annotation?
Thank you for your answer!
Application stack: Spring boot 2.1v+ test containers PostgreSQL 1.10.3v+ JUnit 4.12v
DB testcontainers config
#TestConfiguration
public class DatabaseTestConfig {
private static JdbcDatabaseContainer PSQL;
static {
PSQL = (PostgreSQLContainer) new PostgreSQLContainer("mdillon/postgis:9.4").withUsername("test")
.withPassword("test")
.withDatabaseName("test");
PSQL.start();
Arrays.asList("main_data.sql")
.forEach(DatabaseTestConfig::restoreDump);
/*
set db properties
*/
}
public void restoreDump(String fileName){
/*
insert sql data
PSQL.copyFileToContainer(fileName)...
*/
}
}
Base Integration Test class
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { DatabaseTestConfig.class, ProjectApplication.class })
#ActiveProfiles("test-int")
#AutoConfigureMockMvc
#Sql(scripts = "classpath:extra_data.sql") // insert some extra data for all integration tests
public abstract class AbstractIntTest {
#Autowired
protected MockMvc mockMvc;
Integration Test that calls service where everething happenes
#Transactional
public class SomeIntegrationTest extends AbstractIntTest {
#Before
public void setUp() throws IOException {
//...
}
#Test
public void callServiceTest() throws Exception {
//mockMvc.perform(post(ENDPOINT_URL)
}
Service with simplified logic
#Service
#AllArgsConstructor
public class SomeService {
private final SomeJpaReporistory repo;
private final ExecutorService executor;
#Override
#Transactional
public SomeData call(){
return CompletableFuture.supplyAsync(() -> {
return repo.findAll();
}, executor).exceptionally(e -> {
throw new BadRequestException(e.getMessage());
});
}
When you make the test transactional, the SQL queries in extra_data.sql are performed in a transaction. That transaction is bound to a particular thread and is begun before execution of the test method and rolled back after the test method has completed:
Begin transaction
Execute extra_data.sql
Invoke test method
Roll back transaction
In step 3 you are calling repo.findAll() on a separate thread due to your service's use of supplyAsync. As a transaction is bound to a particular thread, this findAll() call is not part of the transaction in which extra_data.sql was executed. To be able to read the data added by extra_data.sql, it would have to be able to read uncommitted changes and perform a dirty read. Postgres does not support the read uncommitted isolation level so this isn't possible.
You'll need to revisit how you're populating your database with test data or your use of transactions in your tests. Perhaps you could apply extra_data.sql to the database in the same manner as main_data.sql so that it's always in place before any tests are executed and before any transactions are begun.
This is how I've solved this problem:
#Test
#Transactional
#Sql(scripts = "/db/extra_data.sql",
config = #SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
void test() {
// extra_data.sql are executed before this test is run.
}

Calling #Asynchronous metod from library on Wildfly Linux

I've encounter some problem while applying a small library to send email using wildfly email resource
Idea with library is to provide singleton providing asynchronous method to send emails.
in short service looks like
#Singleton
public class MailService {
private static final String MIME_TYPE = "text/html; charset=utf-8";
private static final Logger LOG = Logger.getLogger(MailService.class.getName());
#Inject
private Session session;
#Asynchronous
public void sendEmail(final EmailModel email) {
try {
MimeMessage message = new MimeMessage(session);
if (email.normalRecipientsListIsEmpty()) {
throw new RuntimeException("need destination address.");
}
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email.getNormalRecipients()));
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(email.getCCRecipients()));
message.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(email.getBCCRecipients()));
message.setSubject(email.getSubject());
message.setContent(email.getContent(), MIME_TYPE);
Transport.send(message);
} catch (MessagingException e) {
throw new RuntimeException("Failed to sen email.", e);
}
}
}
Injected session is produced in project via #Produces annotation in Stateless service field.
While on windows everything works fine, however if deployed on wildfly running on linux, there is an timeout exception with message like "could not obtain a lock on method within 5000milis"
When i moved whole code to project, with no changes, everything started to work perfectly.
My question is, why is this happening? Is there a difference in implementation somewhere or in configuration? How can i fix that and move code back to library where it can be reused in other projects?

Injecting a service inside of TimerTask

I need to run daily a process in order to do maintenance work on the server (update records).
I have a singleton scope class that runs a timer and an inner class with the injection of the service I need. When I run the programm the timer throws a NullPointerException because the service has not been injected.
#Named("demonService")
#Singleton
public class DemonImpl implements IDemonService
{
private static Logger log = Logger.getLogger(DemonioImpl.class);
#PostConstruct
public void init()
{
log.info("-->Demon");
Calendar today = new GregorianCalendar();//Every day at 2:00am (from now)
today.set(Calendar.HOUR_OF_DAY, 2);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
try
{
Timer timer = new Timer(true);
timer.schedule(new Updater(), today.getTime(), 24*60*60*1000);
}
catch(Exception e)
{
log.fatal(e.getLocalizedMessage());
e.printStackTrace();
}
log.info("--> Demon: exit");
}
private class Updater extends TimerTask
{
private Logger log = Logger.getLogger(Updater.class);
#Inject
#Named("updaterService")
private IUpdaterService updaterService;
#Override
public void run()
{
log.info("Task: update records (start)");
List<Record> list = updaterService.getAll();//<-- This throws the exception
for(Record item : list)
{
updaterService.update(item);
}
log.info("Task: update records (exit)");
}
}
The error is
Exception in thread "Timer-3" java.lang.NullPointerException
at test.service.impl.DemonImpl$Updater.run(DemonImpl.java:66)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
The application works fine except for this class. How can I inject the service when the application is fully working?
Normally you have a NPE when the Class is not a CDI Bean. If you make new Updater() this is not considered by CDI. you have to #Inject the Updater in your Singleton.
CDI won't manage the instance since you instantiate your Updater by calling the constructor of it yourself.
Now there are two ways to fix this:
Inject an instance of the Updater class in DemonImpl and use that one.
Create a new CDI managed instance at runtime by injecting a Provider<Updater> instance in DemonImpl and get a new instance of the Updater class from it.

Ninject - In what scope DbContext should get binded when RequestScope is meaningless?

In an MVC / WebAPI environment I would use InRequestScope to bind the DbContext.
However, I am now on a Console application / Windows service / Azure worker role (doesn't really matter, just there's no Web request scope), which periodically creates a number of Tasks that run asynchronously. I would like each task to have its own DbContext, and since tasks run on their own thread, I tried binding DbContext using InThreadScope.
Unfortunately, I realize that the DbContext is not disposed when a task is finished. What actually happens is, the thread returns to the Thread Pool and when it is assigned a new task, it already has a DbContext, so DbContexts stay alive forever.
Is there a way InThreadScope can be used here or should I use some other scope? How can ThreadScope be used when threads are returning from ThreadPool every now and then?
If you decide to go on with custom scope, the solution is:
public sealed class CurrentScope : INotifyWhenDisposed
{
[ThreadStatic]
private static CurrentScope currentScope;
private CurrentScope()
{
}
public static CurrentScope Instance => currentScope ?? (currentScope = new CurrentScope());
public bool IsDisposed { get; private set; }
public event EventHandler Disposed;
public void Dispose()
{
this.IsDisposed = true;
currentScope = null;
if (this.Disposed != null)
{
this.Disposed(this, EventArgs.Empty);
}
}
}
Binding:
Bind<DbContext>().To<MyDbContext>().InScope(c => CurrentScope.Instance)
And finally:
using (CurrentScope.Instance)
{
// your request...
// you'll get always the same DbContext inside of this using block
// DbContext will be disposed after going out of scope of this using block
}

Running windows service in separate thread and use autofac for DI

I'm trying to create a long running windows service, so I need to run the actual worker class on a separate thread, to avoid the "service did not respond in a timely fashion" error when I right click and select start in Windows Service Manager.
The worker class ("NotificationProcess") has a whole raft of dependencies and I'm using Autofac to satisfy these.
I'm really not sure how to set up Autofac for the worker class. At the moment I'm getting errors telling me that the DbContext has been disposed when I go to use it in the "Execute" method of the worker class.
I guess I'm looking for how to write a windows service and use a new thread for the worker class with dependencies satisfied by autofac.
I've googled and can't find any examples of this.
Any suggestions would be awesome.
Here's what I've got so far...
Program.cs:
static class Program
{
static void Main()
{
using (var container = ServiceStarter.CreateAutoFacContainer())
{
var service = container.Resolve<NotificationService>();
if (Environment.UserInteractive)
{
service.Debug();
}
else
{
ServiceBase.Run(container.Resolve<NotificationService>());
}
}
The Service class:
public partial class NotificationService : ServiceBase
{
private NotificationProcess _app;
readonly ILifetimeScope _lifetimeScope;
public NotificationService(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_app = _lifetimeScope.Resolve<NotificationProcess>();
_app.Start();
}
The worker class:
public class NotificationProcess
{
private Thread _thread;
private readonly IBankService _bankService;
private readonly IRateService _rateService;
private readonly IEmailService _emailService;
private readonly IRateChangeSubscriberService _rateChangeSubscriberService;
private readonly IRateChangeNotificationService _rateChangeNotificationService;
private readonly ILogManager _logManager;
public NotificationProcess(IBankService bankService, ILogManager logManager, IRateService rateService, IEmailService emailService,
IRateChangeSubscriberService rateChangeSubscriberService, IRateChangeNotificationService rateChangeNotificationService)
{
_bankService = bankService;
_rateService = rateService;
_emailService = emailService;
_rateChangeSubscriberService = rateChangeSubscriberService;
_rateChangeNotificationService = rateChangeNotificationService;
_logManager = logManager;
}
public void Start()
{
_thread = new Thread(new ThreadStart(Execute));
_thread.Start();
}
public void Execute()
{
try
{
var rateChangeToNotify = _rateService.GetRateChangesForNotification();
foreach (var rateChange in rateChangeToNotify)
{
//do whatever business logic.....
}
}
}
The answer is actually simple: use scoping! You should do the following:
Register all services (such as DbContext) that should live for the duration of a request or action with the LifetimeScope lifestyle. You'll usually have a timer in your windows service. Each 'pulse' can be considered a request.
On the beginning of each request begin a lifetime scope.
Within that scope, resolve the root object from the object graph and call its method.
Dispose the scope.
In your case that means you need to change your design, since NotificationService is resolved once and its dependencies are reused on another thread. This is a no-no in dependency injection land.
Here's an alternative design:
// This method is called on a background thread
// (possibly in a timely manner)
public void Run()
{
try
{
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<NotificationService>();
service.Execute();
}
}
catch (Exception ex)
{
// IMPORTANT: log exception.
// Not logging an exception will leave us in the dark.
// Not catching the exception will kill our service
// because we run in a background thread.
}
}
Using a lifetime scope allows you to get a fresh DbContext for every request and it would even allow you to run requests in parallel (with each request its own DbContext).

Resources