Backgroundtask with hot exit the browser

Im writing a backgroundtask that execute procedure my batch written in my oracle database by calling in the public Void run(TaskLifeCycle taskLifeCycle) throws Exception

public void execute(int i) {
        systemAuthenticator.withSystem(() -> {
            String storeProcedure = "BO.PKG_HANDLE_BATCH.SP_HANDLE";
            StoredProcedureQuery query = entityManager.createStoredProcedureQuery(storeProcedure);
            return query.execute();
        });
    }

I have an entity called StepBatch and it have

boolean isSuccess; // (Yes/No)

after that, I want to update the status of the batch if the procedure executed successfully. I try to force-close the browser while the procedure are running.

PROCEDURE SP_HANDLE 
IS 
BEGIN 
    DBMS_LOCK.SLEEP(5); -- sleep 5 seconds
    INSERT INTO test_table 
        VALUES(1,1); -- insert into a dummy table to test
END;

But the procedure still executed successfully but the service doesnt update the success status from No to Yes into my entity.

@Override
public Void run(TaskLifeCycle<Integer> taskLifeCycle) throws Exception {
    for (int i = 0; i < 10; i++) {
        if (taskLifeCycle.isCancelled()) {
            break;
        }
        beforeRun(i); // update some bla bla information
        running(i); // calling my public void execute(int i) in my running method and handle exception
        afterRun(i); // call dataManager.load to get the StepBatch entity and update StepBatch.isSuccess to Yes then dataManager.save(stepBatch);
        i++;
        taskLifeCycle.publish(i);
    }
    return null;
}

My beforeRun just update some neccessary things
My running tried to execute store procedure in my database. I let the procedure sleep 5 second then insert into a dummy table, but while the procedure is sleeping, i try to close the browser
My procedure still commit the work.
but my afterRun doesnt update the status.

How to let my afterRun work?

Do you experience this problem only when you close the browser in the middle of the process?

Regards,
Konstantin

1 Like

I ve created a testcase

@Subscribe(id = "test", subject = "clickListener")
    public void onTestClick(final ClickEvent<JmixButton> event) {
        taskHandler = backgroundWorker.handle(test2());
        taskHandler.execute();
    }
protected BackgroundTask<Integer, Void> test2() {
        return new BackgroundTask<>(10000, TimeUnit.SECONDS) {
            @Override
            public Void run(TaskLifeCycle<Integer> taskLifeCycle) throws Exception {
                for (int i = 0 ; i < 50 ; i ++) {
                    if (taskLifeCycle.isCancelled()) {
                        System.out.println("break");
                        break;
                    }
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("run: " + i);
                    taskLifeCycle.publish(i);
                }
                return null;
            }

            @Override
            public void done(Void result) {
                System.out.println("done: " + result);
            }

            @Override
            public void canceled() {
                System.out.println("canceled");
            }

            @Override
            public boolean handleTimeoutException() {
                System.out.println("handleTimeoutException");
                return super.handleTimeoutException();
            }

            @Override
            public boolean handleException(Exception ex) {
                System.out.println("handleException");
                return super.handleException(ex);
            }

            @Override
            public void progress(List<Integer> changes) {
                System.out.println("PROGRESS: " + changes.get(0));
            }
        };
    }

I would print dummy things to see when I tried to hot-close the browser, will the backgroundtask still run or not.
And yes, backgroundtask wasnt executed in a separate thread independent of the screen.
So if the backgroundtask called a store procedure, when the store procedure was executing (Carrying out a huge amount of work so it take much time) and the browser was closed due to something like electric cut … The store procedure executed successfully with error or no errors, the backgroundtask didnt do anything after that because the attached view was closed.
Is there anyway to make the backgroundtask run in a separated thread when the user press execute button and the backgroundtask didnt depend on the view (such as a backgroundtask as a job without defined it in quarzt-view (jobmodels) ) or async …

If the backgroundtask (BGT for short) is closed (due to the browser is closed) I want one of two cased below happened

  • if a task in the BGT is running that time, everything that only this task alr did before will be rollbacked after finishing.
  • Or the BGT will run separatedly with the view and it will only be stopped by an exception caused by run(TaskLifeCycle taskLifeCycle) and it will execute handleException(Exception ex)

If you want to execute multiple actions in the database atomically, wrap them in a transaction. For example, extract the logic in a Spring bean an annotate its method with @Transactional.

Regards,
Konstantin