Uploaded image for project: 'Sling'
  1. Sling
  2. SLING-5261

Background servlets: use a separate session for captured output

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • Background Servlets 1.0.0
    • Background Servlets 1.0.2
    • Extensions
    • None

    Description

      We use the bgservlet to perform batch actions on content in the background, decoupling it from the user request. We saw a case where these batch actions failed and also no log was written. We have lots of exceptions like this in the log:

      02.11.2015 23:50:32.264 *ERROR* [pool-5743-thread-3] com.day.cq.wcm.msm.impl.commands.RolloutCommand Trying to commit status change: {}
      java.io.IOException: RepositoryException in flush()
              at org.apache.sling.bgservlets.impl.nodestream.NodeOutputStream.flush(NodeOutputStream.java:103)
              at org.apache.sling.bgservlets.impl.nodestream.NodeOutputStream.flushIfNeeded(NodeOutputStream.java:110)
              at org.apache.sling.bgservlets.impl.nodestream.NodeOutputStream.write(NodeOutputStream.java:129)
              at java.io.FilterOutputStream.write(FilterOutputStream.java:71)
              at org.apache.sling.bgservlets.impl.SuspendableOutputStream.write(SuspendableOutputStream.java:65)
              at org.apache.sling.bgservlets.BackgroundHttpServletResponse$ServletOutputStreamWrapper.write(BackgroundHttpServletResponse.java:47)
              at javax.servlet.ServletOutputStream.print(ServletOutputStream.java:101)
              at javax.servlet.ServletOutputStream.println(ServletOutputStream.java:252)
           ...
      Caused by: javax.jcr.InvalidItemStateException: OakState0001: Unresolved conflicts in /content/foo/bar/jcr:content
              at org.apache.jackrabbit.oak.api.CommitFailedException.asRepositoryException(CommitFailedException.java:237)
              at org.apache.jackrabbit.oak.api.CommitFailedException.asRepositoryException(CommitFailedException.java:212)
              at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.newRepositoryException(SessionDelegate.java:664)
              at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.save(SessionDelegate.java:489)
              at org.apache.jackrabbit.oak.jcr.session.SessionImpl$8.performVoid(SessionImpl.java:406)
              at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.performVoid(SessionDelegate.java:268)
              at org.apache.jackrabbit.oak.jcr.session.SessionImpl.save(SessionImpl.java:403)
              at org.apache.sling.bgservlets.impl.DeepNodeCreator.deepCreateNode(DeepNodeCreator.java:60)
              at org.apache.sling.bgservlets.impl.nodestream.NodeOutputStream.flush(NodeOutputStream.java:92)
              ... 134 common frames omitted
      Caused by: org.apache.jackrabbit.oak.api.CommitFailedException: OakState0001: Unresolved conflicts in /content/foo/bar/jcr:content
              at org.apache.jackrabbit.oak.plugins.commit.ConflictValidator.failOnMergeConflict(ConflictValidator.java:115)
              at org.apache.jackrabbit.oak.plugins.commit.ConflictValidator.propertyChanged(ConflictValidator.java:90)
              at org.apache.jackrabbit.oak.spi.commit.CompositeEditor.propertyChanged(CompositeEditor.java:91)
              at org.apache.jackrabbit.oak.spi.commit.EditorDiff.propertyChanged(EditorDiff.java:93)
              at org.apache.jackrabbit.oak.spi.state.AbstractNodeState.comparePropertiesAgainstBaseState(AbstractNodeState.java:181)
              at org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore.compare(DocumentNodeStore.java:1394)
              at org.apache.jackrabbit.oak.plugins.document.DocumentNodeState.compareAgainstBaseState(DocumentNodeState.java:344)
              at org.apache.jackrabbit.oak.spi.commit.EditorDiff.childNodeChanged(EditorDiff.java:148)
              at org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore.dispatch(DocumentNodeStore.java:2108)
           ...
      

      The exception happens when writing to the output stream (which is redirected to write to the repo somewhere below /var/bg), but it logs a conflict in /content.

      For me it looks like that the session which is attached to the user request is used for 2 different aspects:

      • processing the actions on the content
      • logging the output to the repository

      check the BackgroundRequestExecutionJob class, where the „resource resolver“ is used for both constructing the „response“ object and as parameter into the slingRequestProcessor.processRequest() call.

      For me it looks like if an repository exception happens on on the processing side, this effectively prevents the writing to the output stream as well (as seen by the path where this OakState0001 exception is being reported). I think, that the action doesn’t clear the JCR transient space after an exception which will cause any subsequent session.save() to fail as well.

      While we could consider this as a problematic case in the handling of the request itself, the bgservlets should at least be capable to store any issue written to the output stream successfully in the repository. So a dedicated session to write the output would be very good to have.

      But there is also a different problem with the current implementation: When the request fills the transient space and does call session.save() yet, but rather writes to the outpustream, it might be case that the bgservlets do the session.save(), thus saving the transient space created by the regular execution as well.

      So I suggest this patch:

      Index: BackgroundRequestExecutionJob.java
      ===================================================================
      --- BackgroundRequestExecutionJob.java    (revision 1710381)
      +++ BackgroundRequestExecutionJob.java    (working copy)
      @@ -50,6 +50,7 @@
           private final BackgroundHttpServletResponse response;
           private final SuspendableOutputStream stream;
           private final ResourceResolver resourceResolver;
      +    private final ResourceResolver bgResponseResolver;
           private final SlingRequestProcessor slingRequestProcessor;
           private final String path;
           private final String streamPath;
      @@ -72,8 +73,11 @@
               // current request, for the background request.
               resourceResolver = request.getResourceResolver().clone(null);
      
      +    // create a dedicated session for the response object
      +    bgResponseResolver = request.getResourceResolver().clone(null);
      +
               // Get JobData, defines path and used to save servlet output to the repository
      -        final Session s = resourceResolver.adaptTo(Session.class);
      +        final Session s = bgResponseResolver.adaptTo(Session.class);
               if(s == null) {
                   throw new IOException("Unable to get Session from ResourceResolver " + resourceResolver);
               }
      @@ -110,6 +114,8 @@
      
                   // cleanup the resource resolver
                   resourceResolver.close();
      +        bgResponseResolver.close();
      +
               }
           }
      

      Attachments

        Issue Links

          Activity

            People

              bdelacretaz Bertrand Delacretaz
              joerghoh Joerg Hoh
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: