Thursday, March 14, 2019

Spring Boot Micro services - tmp/tomcat working directory gets deleted & unable to perform any multi part upload


Hello friends, Today in this blog we will talk on the below error, which might occur within your Spring boot application.


2019-03-13 00:56:34.824 ERROR 3061 --- [nio-8080-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : 
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request 
processing failed; nested exception is org.springframework.web.multipart.MultipartException: Failed 
to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload 
location [/tmp/tomcat.8182395428229892866.8080/work/Tomcat/localhost/ROOT] is not valid] with root cause

java.io.IOException: The temporary upload location [/tmp/tomcat.8182395428229892866.8080/work/Tomcat/localhost/ROOT] is not valid
 at org.apache.catalina.connector.Request.parseParts(Request.java:2877) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
 at org.apache.catalina.connector.Request.parseParameters(Request.java:3242) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
 at org.apache.catalina.connector.Request.getParameter(Request.java:1136) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
 at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
 at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:84) ~[spring-web-5.0.9.RELEASE.jar!/:5.0.9.RELEASE]
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar!/:5.0.9.RELEASE]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]


If your spring boot application deals with the multipart request, and there are no multipart request from last 10 days (default value for most of Linux) then your Linux operating system deletes the tomcat working directory as part of tmp directory cleanup activity.

So what is the solution to this problem

  • Use the alternate directory for storing temp files using property "java.io.tmpdir"
  • Configure "tmpwatch" process to ignore the tomcat folder for cleanup

You must be familiar with the first approach i.e. setting the java.io.tmpdir property to the location, where you know that no other process will clean up this location. You can clean up this location in your application startup/shutdown scripts to ensure that no stale directory be there longer. You can pass the -Djava.io.tmpdir=/var/tmp Parameter while running your application


Let's discuss the second approach.
Here in this approach, we are adding configuration in the tmpwatch configuration file to tell the process to ignore the /tmp/tomcat* folders. The tmpwatch configuration location will be at /etc/cron.daily/tmpwatch.

File look like below
flags=-umc
/usr/sbin/tmpwatch "$flags" -x /tmp/.X11-unix -x /tmp/.XIM-unix \
         -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix \
         -X '/tmp/hsperfdata_*' -X '/tmp/.hdb*lock' \
         -X '/tmp/.sapstartsrv*.log' \
         -X '/tmp/pymp-*' 10d /tmp
/usr/sbin/tmpwatch "$flags" 30d /var/tmp
for d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; do
     if [ -d "$d" ]; then
         /usr/sbin/tmpwatch "$flags" -f 30d "$d"
     fi
done

You need to add the tomcat folder in the above file. So that whenever the tmpwatch process runs, it should ignore the tomcat folder for deletion.

Here is the modified file. Please, note that we have used -X & not -x. Both tell the process to exclude the specified directory from deletion. Using -X we can give a directory path with wildcard characters but with -x we can only give fixed path.

flags=-umc
/usr/sbin/tmpwatch "$flags" -x /tmp/.X11-unix -x /tmp/.XIM-unix \
         -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix \
         -X '/tmp/hsperfdata_*' -X '/tmp/.hdb*lock' \
         -X '/tmp/.sapstartsrv*.log' \
         -X '/tmp/tomcat* \
         -X '/tmp/pymp-*' 10d /tmp
/usr/sbin/tmpwatch "$flags" 30d /var/tmp
for d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; do
     if [ -d "$d" ]; then
         /usr/sbin/tmpwatch "$flags" -f 30d "$d"
     fi
done


So that's all for this blog I hope you have understood both approaches. If you have any question, suggestion please let us know in the comment box below. I will definitely try to answer your question or consider your suggestion to improve my blogs.

Thanks
Have a wonderful day & Happy Coding !!!

3 comments:

  1. please explain clearly with examples for first approach.

    ReplyDelete
  2. Hi first approach is quite simple and straight forward. In the first approach you just have to set the java.io.tmpdir property like example . . .

    java -Djava.io.tmpdir=/path/to/tmpdir -jar YourSpringBootApp.jar

    make sure that path to the temp directory should not be /var/tmp or /tmp in linux. these directory are cleaned-up periodically by linux tmpwatch process which will put you in to same issue.

    ReplyDelete
  3. This comment has been removed by a blog administrator.

    ReplyDelete