Expand my Community achievements bar.

SOLVED

Closing ResourceResolver and Session

Avatar

Level 4

Hi All,

In order to avoid the below error, I am creating resourceresolver and session at every place(all methods) and closing it at the end of method in finally block.. Sample piece of code for creating and closing resourceresolver and session in single method

I am doing lot of operations(remove node, add/modify/delete property under the node) in 30 different methods. Whether it will cause any performance issue if we creating and closing resourceresolver and session at 30 methods. 

Error:

01.01.2016 09:21:56.916 *WARN* [0:0:0:0:0:0:0:1 [1424679716845] GET /content/geometrixx/en/services.html HTTP/1.0] org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate Attempt to perform hasProperty while another thread is concurrently reading from session-494. Blocking until the other thread is finished using this session. Please review your code to avoid concurrent use of a session.

java.lang.Exception: Stack trace of concurrent access to session-494

at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.perform(SessionDelegate.java:276)

at org.apache.jackrabbit.oak.jcr.session.ItemImpl.perform(ItemImpl.java:113)

at org.apache.jackrabbit.oak.jcr.session.NodeImpl.hasProperty(NodeImpl.java:812)

at org.apache.sling.jcr.resource.JcrPropertyMap.read(JcrPropertyMap.java:350)

 

Sample piece of code :

ResourceResolver resolver = null;
Session session = null;

        try {

            resolver = resolverFactory.getServiceResourceResolver(null);

            session = resolver.adaptTo(Session.class);

            Node test= session.getNode("/content/dam");

           updateproperty(test);

            session.save();

            }

        } catch (Exception e) {

            Logging exception

        } finally {

            if (session != null && session.isLive()) {

                session.logout();

            }

        if (resolver != null && resolver.isLive()) {

            resolver.close();

        }

        }

1 Accepted Solution

Avatar

Correct answer by
Community Advisor
14 Replies

Avatar

Employee

Make sure that these session and resolver variables are also declared locally.

Personally I tend to avoid to 'create' sessions, but use the one attached from the request/user.

Also using ModifiableValueMap will make things easier.

Avatar

Level 10

As @Jitendra mentioned, it really depends on how and what are you doing with session. Best practice is to create and close the session where ever necessary instead of creating it globally !

Avatar

Level 4

Thanks for your reply..

Scenario :

Copying child nodes from particular node(/content/old/node1) and replacing child nodes under path /content/new/node1.Also doing add/modify/delete property under the node /content/new/node1 and its child nodes.
Similarly (/content/old/node2) to (/content/new/node2)
(/content/old/node3) to (/content/new/node3)
(/content/old/node4) to (/content/new/node4)

I am doing the above four operation at same time(creating job for each process /content/old/node1 to /content/new/node1). Four job is running parallel.

Initial call came to job class and it is directing to job service. In job service, I created resourceresolver 
from resourceresolverfactory(org.apache.sling.api.resource) and made resourceresolver as global variable for creating session at various private lower level methods.

Example:

Private ResourceResolver resolver

Class Jobservice(){
public void mainmethod(){
resolver = resourceresolverfactory.getServiceResourceResolver(null);
String path = "/content/old/node1";
lowerMethod1(path)
}

private void lowerMethod1(String path){
Session session= resolver.adapt(Session.class);
Node destinationNode = session.getNode("/content/new/node1");
deleteAllCHildNodes(destinationNode);
updateProperty(destinationNode);
}

private void deleteAllCHildNodes(Node destNode){
Session session= resolver.adapt(Session.class);
 ---deleting all childnodes under destNode----
 session.save();
}

Likewise I am doing different operation under /content/new/node1. I was getting concurrent access error and invaliditemstateexception(item doesi not exist anymore) at the different places in my code 
because four jobs are running parallel and performing operation under the respective node. I came to know that sessions are 
opening long time by google search(https://cqdump.wordpress.com/2015/03/02/aem-scaling-patterns-avoid-shared-sessions/) abt this issue. 
Also changes done for node1 in session1(first job) will not be available in session2(opened in second job). 

In order to avoid this error, I am creating resourceresolver and session at lower level methods and closing at the end of method itself(Session is opening for short duration) as below

Class Jobservice(){
public void mainmethod(){
ResourceResolver resolver = null;
Session session = null;
try {
    resolver = resolverFactory.getServiceResourceResolver(null);
    session = resolver.adaptTo(Session.class);
    String path = "/content/old/node1";
    lowerMethod1(path);
} catch (Exception e) {
     Logging exception
} finally {

            if (session != null && session.isLive()) {
            session.logout(); 
            }
        if (resolver != null && resolver.isLive()) {
        resolver.close();
        }
        }
}

private void lowerMethod1(String path){
ResourceResolver resolver = null;
Session session = null;
try {
    resolver = resolverFactory.getServiceResourceResolver(null);
    session = resolver.adaptTo(Session.class);
    Node destinationNode = session.getNode("/content/new/node1");
    deleteAllCHildNodes(destinationNode);
    updateProperty(destinationNode);
    } catch (Exception e) {
     Logging exception
} finally {
if (session != null && session.isLive()) {
    session.logout(); 
}
if (resolver != null && resolver.isLive()) {
    resolver.close();
}
}
}

private void deleteAllCHildNodes(Node destNode){
ResourceResolver resolver = null;
Session session = null;
try {
resolver = resolverFactory.getServiceResourceResolver(null);
 session= resolver.adapt(Session.class);
 ---deleting all childnodes under destNode----
 session.save();
     } catch (Exception e) {
     Logging exception
} finally {
if (session != null && session.isLive()) {
    session.logout(); 
}
if (resolver != null && resolver.isLive()) {
    resolver.close();
}
}
}
 
Kindly share your thoughts on this one.. whether it is good practice to do create and close resourceresolver and session in single method and it will cause any performance issue because mostly maximum no of jobs(10) will run in parallel.
Please suggest any other ideas to handle the concurrent issue if my idea is not good. 

Avatar

Level 4

Thanks for your reply..

Scenario :

Copying child nodes from particular node(/content/old/node1) and replacing child nodes under path /content/new/node1.Also doing add/modify/delete property under the node /content/new/node1 and its child nodes.
Similarly (/content/old/node2) to (/content/new/node2)
(/content/old/node3) to (/content/new/node3)
(/content/old/node4) to (/content/new/node4)

I am doing the above four operation at same time(creating job for each process /content/old/node1 to /content/new/node1). Four job is running parallel.

Initial call came to job class and it is directing to job service. In job service, I created resourceresolver 
from resourceresolverfactory(org.apache.sling.api.resource) and made resourceresolver as global variable for creating session at various private lower level methods.

Example:

Private ResourceResolver resolver

Class Jobservice(){
public void mainmethod(){
resolver = resourceresolverfactory.getServiceResourceResolver(null);
String path = "/content/old/node1";
lowerMethod1(path)
}

private void lowerMethod1(String path){
Session session= resolver.adapt(Session.class);
Node destinationNode = session.getNode("/content/new/node1");
deleteAllCHildNodes(destinationNode);
updateProperty(destinationNode);
}

private void deleteAllCHildNodes(Node destNode){
Session session= resolver.adapt(Session.class);
 ---deleting all childnodes under destNode----
 session.save();
}

Likewise I am doing different operation under /content/new/node1. I was getting concurrent access error and invaliditemstateexception(item doesi not exist anymore) at the different places in my code 
because four jobs are running parallel and performing operation under the respective node. I came to know that sessions are 
opening long time by google search(https://cqdump.wordpress.com/2015/03/02/aem-scaling-patterns-avoid-shared-sessions/) abt this issue. 
Also changes done for node1 in session1(first job) will not be available in session2(opened in second job). 

In order to avoid this error, I am creating resourceresolver and session at lower level methods and closing at the end of method itself(Session is opening for short duration) as below

Class Jobservice(){
public void mainmethod(){
ResourceResolver resolver = null;
Session session = null;
try {
    resolver = resolverFactory.getServiceResourceResolver(null);
    session = resolver.adaptTo(Session.class);
    String path = "/content/old/node1";
    lowerMethod1(path);
} catch (Exception e) {
     Logging exception
} finally {

            if (session != null && session.isLive()) {
            session.logout(); 
            }
        if (resolver != null && resolver.isLive()) {
        resolver.close();
        }
        }
}

private void lowerMethod1(String path){
ResourceResolver resolver = null;
Session session = null;
try {
    resolver = resolverFactory.getServiceResourceResolver(null);
    session = resolver.adaptTo(Session.class);
    Node destinationNode = session.getNode("/content/new/node1");
    deleteAllCHildNodes(destinationNode);
    updateProperty(destinationNode);
    } catch (Exception e) {
     Logging exception
} finally {
if (session != null && session.isLive()) {
    session.logout(); 
}
if (resolver != null && resolver.isLive()) {
    resolver.close();
}
}
}

private void deleteAllCHildNodes(Node destNode){
ResourceResolver resolver = null;
Session session = null;
try {
resolver = resolverFactory.getServiceResourceResolver(null);
 session= resolver.adapt(Session.class);
 ---deleting all childnodes under destNode----
 session.save();
     } catch (Exception e) {
     Logging exception
} finally {
if (session != null && session.isLive()) {
    session.logout(); 
}
if (resolver != null && resolver.isLive()) {
    resolver.close();
}
}
}
 
Kindly share your thoughts on this one.. whether it is good practice to do create and close resourceresolver and session in single method and it will cause any performance issue because mostly maximum no of jobs(10) will run in parallel.
Please suggest any other ideas to handle the concurrent issue if my idea is not good. 

Avatar

Level 4

Thanks for your reply..

Scenario :

Copying child nodes from particular node(/content/old/node1) and replacing child nodes under path /content/new/node1.Also doing add/modify/delete property under the node /content/new/node1 and its child nodes.
Similarly (/content/old/node2) to (/content/new/node2)
(/content/old/node3) to (/content/new/node3)
(/content/old/node4) to (/content/new/node4)

I am doing the above four operation at same time(creating job for each process /content/old/node1 to /content/new/node1). Four job is running parallel.

Initial call came to job class and it is directing to job service. In job service, I created resourceresolver 
from resourceresolverfactory(org.apache.sling.api.resource) and made resourceresolver as global variable for creating session at various private lower level methods.

Example:

Private ResourceResolver resolver

Class Jobservice(){
public void mainmethod(){
resolver = resourceresolverfactory.getServiceResourceResolver(null);
String path = "/content/old/node1";
lowerMethod1(path)
}

private void lowerMethod1(String path){
Session session= resolver.adapt(Session.class);
Node destinationNode = session.getNode("/content/new/node1");
deleteAllCHildNodes(destinationNode);
updateProperty(destinationNode);
}

private void deleteAllCHildNodes(Node destNode){
Session session= resolver.adapt(Session.class);
 ---deleting all childnodes under destNode----
 session.save();
}

Likewise I am doing different operation under /content/new/node1. I was getting concurrent access error and invaliditemstateexception(item doesi not exist anymore) at the different places in my code 
because four jobs are running parallel and performing operation under the respective node. I came to know that sessions are 
opening long time by google search(https://cqdump.wordpress.com/2015/03/02/aem-scaling-patterns-avoid-shared-sessions/) abt this issue. 
Also changes done for node1 in session1(first job) will not be available in session2(opened in second job). 

In order to avoid this error, I am creating resourceresolver and session at lower level methods and closing at the end of method itself(Session is opening for short duration) as below

Class Jobservice(){
public void mainmethod(){
ResourceResolver resolver = null;
Session session = null;
try {
    resolver = resolverFactory.getServiceResourceResolver(null);
    session = resolver.adaptTo(Session.class);
    String path = "/content/old/node1";
    lowerMethod1(path);
} catch (Exception e) {
     Logging exception
} finally {

            if (session != null && session.isLive()) {
            session.logout(); 
            }
        if (resolver != null && resolver.isLive()) {
        resolver.close();
        }
        }
}

private void lowerMethod1(String path){
ResourceResolver resolver = null;
Session session = null;
try {
    resolver = resolverFactory.getServiceResourceResolver(null);
    session = resolver.adaptTo(Session.class);
    Node destinationNode = session.getNode("/content/new/node1");
    deleteAllCHildNodes(destinationNode);
    updateProperty(destinationNode);
    } catch (Exception e) {
     Logging exception
} finally {
if (session != null && session.isLive()) {
    session.logout(); 
}
if (resolver != null && resolver.isLive()) {
    resolver.close();
}
}
}

private void deleteAllCHildNodes(Node destNode){
ResourceResolver resolver = null;
Session session = null;
try {
resolver = resolverFactory.getServiceResourceResolver(null);
 session= resolver.adapt(Session.class);
 ---deleting all childnodes under destNode----
 session.save();
     } catch (Exception e) {
     Logging exception
} finally {
if (session != null && session.isLive()) {
    session.logout(); 
}
if (resolver != null && resolver.isLive()) {
    resolver.close();
}
}
}
 
Kindly share your thoughts on this one.. whether it is good practice to do create and close resourceresolver and session in single method and it will cause any performance issue because mostly maximum no of jobs(10) will run in parallel.
Please suggest any other ideas to handle the concurrent issue if my idea is not good. 

Avatar

Employee

Always use local variables in this case.

Avatar

Level 9

Hey sankarr26533925,

I don't know how are you creating jobs. But here is the solution of your problem using Java ExecuterFramework for multi-threaded application. Even if you are not using any framework and simply creating Threads then follow the same concept. Without a framework, you might have to take care of synchronization in jobService methods.

//Job Class

public class Job implements Callable{

           final ResourceResolver resourceResolver, JobService jobService;

         Job(ResourceResolver resourceResolver, JobService jobService,  /** you can pass other arguments here**/){

                this.resouceResolver = resourceResolver; this.jobService = jobService;

         }        

        @Override
    public String call() throws Exception// invoke methods for node operations from here.

            jobService.initOperations(resourceResolver); // user resourceResolver in job service get session & saving nodes property. But don't close this.

    }

 }

//This is the class where you initiate jobs.

class MainClass {

   // Get resouceResolver here and pass it to jobs. And when all your jobs are done, close resolver here in a finally block.

}

Jitendra

Avatar

Level 4

I am using JobConsumer API (org.apache.sling.event.jobs.consumer). I should use CQ5 API only..Can we pass resourceresolver through Job properties ?

Avatar

Level 4

So I can create session and resolver in each method. Will it cause any problem ?

Avatar

Level 4

Can I create resourceresolver in local method and close it ?

Avatar

Level 10

Technically you can do that but ideally, you should declare it globally for the service which can be used to complete a flow or a transaction and then make your master method to have the finally block to close the session or resourceresolver.

If you have multiple method which works independently, then you can still have the local variables

Avatar

Employee Advisor

sankarr26533925 wrote...

Can I create resourceresolver in local method and close it ?

 

That's perfectly possible.

Avatar

Level 9

@sankarr26533925,

I don't think that could solve your problem. But you can try it. I think, at the job level, Open resourceResolver & close it, but make sure it is in a synchronized block.

Jitendra

Avatar

Correct answer by
Community Advisor