Issue #2855: Catching exceptions from online backup

Type: Feature RequestVersion: 2.8.8Priority: NormalStatus: FixedReplies: 10
#1

Hello,

I have a request for improvement in the area of backuping.

For catching the exceptions during online backups, I am using the solution suggested in the post 2786

Well not exactly, because there is written to use Thread.setDefaultUncaughtExceptionHandler() which is a global handler for all threads of the JVM and it is already used for other purpose in our app, so we are using the following solution:

Thread backupThread = backupQuery.getSingleResult();
backupThread.setUncaughtExceptionHandler((t, e) -> {
    // handle the exception in the way we would like
});
            
// Wait until the backup is completed.
try {
    backupThread.join();
} catch (InterruptedException e) {
    e.printStackTrace();
}

But it does not work well. For small database files in cases the exception is risen in the beginning of the backup process, then the backupThread finished its work even before our code would set the exception handler on the backupThread object.

So we lose the exception and our backup process acts as it would have run fine.

However the backupThread object has the exception stored in itself in field 'a', like u can see on the attached screen.

So my suggestion is that You could either make this field accessible via some API or the 

TypedQuery.getSingleResult()

would accept a parameter of type 

UncaughtExceptionHandler

which would be set on the executing thread before the execution starts.

That way we would not lose the exceptions in the beginning of the backuping.

 

#2

Does the setUncaughtExceptionHandler solution currently work also in client-server mode (when it is not an immediate exception)?

Maybe a query hint to disable starting the threads automatically will be a more flexible extension? i.e. your application will call Thread's start when ready after setting the Thread object?

ObjectDB Support
#3

Yes, the

setUncaughtExceptionHandler

method works in client-server mode. The query hint to disable automatic starting of the backup thread would be nice solution for us.

#4

Please check build 2.8.9_02 with something like:

    TypedQuery backupQuery =
        em.createQuery("objectdb backup", Thread.class);
    backupQuery.setParameter("start", false);
    Thread backupThread = backupQuery.getSingleResult();
    // TODO: Complete initializing the thread.
    backupThread.start();
    backupThread.join();
ObjectDB Support
#5

I tested the improvement and the delayed starting is working. However if the file which I set in the target attribute, is not accessible for the app, a UserException is risen, but it is caught in the TOL.run() method instead of letting the 

UncaughtExceptionHandler

to catch it.

There is some handling of the exception like writing it into the log file with trace level, which is in fact making it invisible and then the exception is ignored. The backup query ends successfully although there was an Exception in it. I attached a screenshot from the debugger.

 

#6

Please try build 2.8.9_03.

ObjectDB Support
#7

I tried the new build. It did not help. You've added these 2 lines to the catch block in TOL:58 as shown on the attached screen:

this.a().a("tool").f(var3);
throw new InternalException(var4);

But this catch block is not reached as the exception is caught in the surrounding catch block in TOL:47 and its code does not generate next exception.

It would suggest moving the

throw new InternalException(var4);

to the finally block instead of the inner catch block.

 

#8

Maybe the catch block is executed but there is an unexpected exception in that catch block. In addition, there is already an internal mechanism of transferring the exception to another thread, which may interfere with what you are doing.

Could you please explain how to reproduce the exact situation using simple code, similar to the code in #4 above, with step by step instructions?

ObjectDB Support
#9

My simplified code for doing the backups is the following:

EntityManager em = database.createEntityManager();
try {
    TypedQuery backupQuery = em.createQuery("objectdb backup", Thread.class);
    backupQuery.setParameter("target", "/someNotExistingPath/withoutCreateAccess");
    backupQuery.setParameter("name", "20231012");
    backupQuery.setParameter("start", false);
    Thread backupThread = backupQuery.getSingleResult();
    backupThread.setUncaughtExceptionHandler((t, e) -> {
        error("Failed backup of " + database.getDbName(), e);
    });
    backupThread.start();
    
    // Wait until the backup is completed.
    try {
        backupThread.join();
    } catch (InterruptedException e) {
        LOG.error(e);
    }
} finally {
    if (em.isOpen()) {
        em.close();
    }    
}

 I was debugging the process and saw the first catch block in TOL caught the UserException, but there was no additional exception, so the inner catch block was skipped over. The UserException was raised after some File.mkdirs() method failed to create the missing directories, so the important part is to set as "target" a not existing Path, which should be created via the Backup, but it fails to create it due to missing file permissions.

#10

Please try build 2.8.9_04.

ObjectDB Support
#11

It works nicely in the latest build.

Thx!

Reply